mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2026-10-24 23:02:27 +00:00
Fleshing out the FileStoreFactory (lots of duplicate code with the FormattedDiskFactory).
This commit is contained in:
1 parent
907509631b
commit
7d0742e4cc
1 file changed
+164
-5
@@ -20,6 +20,7 @@
|
||||
package org.applecommander.filestore;
|
||||
|
||||
import com.webcodepro.applecommander.storage.DiskConstants;
|
||||
import org.applecommander.device.*;
|
||||
import org.applecommander.device.nibble.NibbleTrackReaderWriter;
|
||||
import org.applecommander.hint.Hint;
|
||||
import org.applecommander.image.NibbleImage;
|
||||
@@ -28,12 +29,33 @@ import org.applecommander.source.Source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The FileStoreFactory inspects a given Source to see if it matches any known file store(s).
|
||||
* Invoke via {@link FileStores#inspect(Source)} which will return a Context. The Context _can be empty_.
|
||||
* Note that most logic is deferred to the "old" AppleCommander APIs for the time being.
|
||||
*/
|
||||
/// The FileStoreFactory inspects a given Source to see if it matches any known file store(s).
|
||||
/// Invoke via [FileStores#inspect(Source)] which will return a Context. The Context _can be empty_.
|
||||
/// If this is the case, devices can be created via the [FileStoreFactory.Context#blockDevice()] and
|
||||
/// [Context#trackSectorDevice()] builders.
|
||||
///
|
||||
/// The builders follow the observation about what each filesystem currently uses:
|
||||
///
|
||||
/// | OS | 13-sector | 16-sector | 800K | HDV |
|
||||
/// | :--- | :--- | :--- | :--- | :--- |
|
||||
/// | CP/M | - | CP/M | - | - |
|
||||
/// | DOS | Physical | DOS | Pascal | - |
|
||||
/// | GameDOS | - | DOS | - | - |
|
||||
/// | Gutenberg | - | DOS | - | - |
|
||||
/// | NakedOS | - | Physical | - | - |
|
||||
/// | Pascal | - | Pascal | Pascal | Pascal |
|
||||
/// | RDOS | Physical | DOS | - | - |
|
||||
///
|
||||
/// * 13-sector disks are only track/sector devices. (And RDOS has a unique mapping to 256 byte blocks).
|
||||
/// * 16-sector disks have a variety of sector mappings. It can also double as a "standard" 512 byte block,
|
||||
/// as well as a unique CP/M 1024 block device.
|
||||
/// * 800K disks are only standard 512 byte block (Prodos or Pascal). OzDOS and UniDOS do have unique
|
||||
/// mappings to track and sector, but logically, they are block devices.
|
||||
/// * Anything else (larger than 800K) are "hard-disk" images and only blocks.
|
||||
///
|
||||
/// Note that much of this logic is deferred to the "old" AppleCommander APIs for the time being.
|
||||
public interface FileStoreFactory {
|
||||
void inspect(Context ctx);
|
||||
|
||||
@@ -55,5 +77,142 @@ public interface FileStoreFactory {
|
||||
nibbleTrackReaderWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockDeviceBuilder blockDevice() {
|
||||
return new BlockDeviceBuilder(this);
|
||||
}
|
||||
public static class BlockDeviceBuilder {
|
||||
private final Context ctx;
|
||||
private final List<BlockDevice> devices = new ArrayList<>();
|
||||
private BlockDeviceBuilder(Context ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
public BlockDeviceBuilder include16Sector(Hint hint) {
|
||||
if (ctx.nibbleTrackReaderWriter != null) {
|
||||
Optional<TrackSectorDevice> nibble = TrackSectorNibbleDevice.identify(ctx.nibbleTrackReaderWriter);
|
||||
if (nibble.isPresent()) {
|
||||
TrackSectorDevice converted = switch (hint) {
|
||||
case DOS_SECTOR_ORDER -> SkewedTrackSectorDevice.physicalToDosSkew(nibble.get());
|
||||
case PRODOS_BLOCK_ORDER -> SkewedTrackSectorDevice.physicalToPascalSkew(nibble.get());
|
||||
case NIBBLE_SECTOR_ORDER -> nibble.get();
|
||||
default -> throw new RuntimeException("wrong hint type: " + hint);
|
||||
};
|
||||
devices.add(new TrackSectorToBlockAdapter(converted, TrackSectorToBlockAdapter.BlockStyle.PRODOS));
|
||||
}
|
||||
}
|
||||
else if (ctx.source.isApproxBetween(DiskConstants.APPLE_140KB_DISK, DiskConstants.APPLE_160KB_DISK)) {
|
||||
if (ctx.source.is(Hint.DOS_SECTOR_ORDER) || ctx.source.extensionLike("do")) {
|
||||
TrackSectorDevice doDevice = new DosOrderedTrackSectorDevice(ctx.source, Hint.DOS_SECTOR_ORDER);
|
||||
TrackSectorDevice poDevice = SkewedTrackSectorDevice.dosToPascalSkew(doDevice);
|
||||
devices.add(new TrackSectorToBlockAdapter(poDevice, TrackSectorToBlockAdapter.BlockStyle.PRODOS));
|
||||
}
|
||||
else if (ctx.source.is(Hint.PRODOS_BLOCK_ORDER) || ctx.source.extensionLike("po")) {
|
||||
devices.add(new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE));
|
||||
}
|
||||
else {
|
||||
devices.add(new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE));
|
||||
TrackSectorDevice doDevice = new DosOrderedTrackSectorDevice(ctx.source, Hint.DOS_SECTOR_ORDER);
|
||||
TrackSectorDevice poDevice = SkewedTrackSectorDevice.dosToPascalSkew(doDevice);
|
||||
devices.add(new TrackSectorToBlockAdapter(poDevice, TrackSectorToBlockAdapter.BlockStyle.PRODOS));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public BlockDeviceBuilder include800K() {
|
||||
if (ctx.source.isApproxEQ(DiskConstants.APPLE_800KB_DISK)) {
|
||||
devices.add(new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public BlockDeviceBuilder includeHDV() {
|
||||
// Anything not a floppy is included -- but if we have a device, assume it was picked up elsewhere...
|
||||
if (ctx.source.getSize() > DiskConstants.APPLE_140KB_NIBBLE_DISK && devices.isEmpty()) {
|
||||
devices.add(new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public List<BlockDevice> get() {
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
||||
public TrackSectorDeviceBuilder trackSectorDevice() {
|
||||
return new TrackSectorDeviceBuilder(this);
|
||||
}
|
||||
public static class TrackSectorDeviceBuilder {
|
||||
private final Context ctx;
|
||||
private final List<TrackSectorDevice> devices = new ArrayList<>();
|
||||
private TrackSectorDeviceBuilder(Context ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
public TrackSectorDeviceBuilder include13Sector() {
|
||||
if (ctx.nibbleTrackReaderWriter != null) {
|
||||
Optional<TrackSectorDevice> nibble = TrackSectorNibbleDevice.identify(ctx.nibbleTrackReaderWriter);
|
||||
nibble.ifPresent(device -> {
|
||||
if (device.getGeometry().sectorsPerTrack() == 13) {
|
||||
devices.add(device);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (ctx.source.isApproxEQ(DiskConstants.APPLE_13SECTOR_DISK)) {
|
||||
devices.add(new DosOrderedTrackSectorDevice(ctx.source));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public TrackSectorDeviceBuilder include16Sector(Hint hint) {
|
||||
assert hint == Hint.DOS_SECTOR_ORDER || hint == Hint.NIBBLE_SECTOR_ORDER;
|
||||
if (ctx.nibbleTrackReaderWriter != null) {
|
||||
Optional<TrackSectorDevice> nibble = TrackSectorNibbleDevice.identify(ctx.nibbleTrackReaderWriter);
|
||||
nibble.ifPresent(device -> {
|
||||
if (device.getGeometry().sectorsPerTrack() == 16) {
|
||||
TrackSectorDevice converted = switch (hint) {
|
||||
case DOS_SECTOR_ORDER -> SkewedTrackSectorDevice.physicalToDosSkew(nibble.get());
|
||||
case NIBBLE_SECTOR_ORDER -> nibble.get();
|
||||
default -> throw new RuntimeException("wrong hint type: " + hint);
|
||||
};
|
||||
devices.add(converted);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (ctx.source.isApproxBetween(DiskConstants.APPLE_140KB_DISK, DiskConstants.APPLE_160KB_DISK)) {
|
||||
TrackSectorDevice doDevice = null;
|
||||
TrackSectorDevice poDevice = null;
|
||||
if (ctx.source.is(Hint.DOS_SECTOR_ORDER) || ctx.source.extensionLike("do")) {
|
||||
doDevice = new DosOrderedTrackSectorDevice(ctx.source, Hint.DOS_SECTOR_ORDER);
|
||||
}
|
||||
else if (ctx.source.is(Hint.PRODOS_BLOCK_ORDER) || ctx.source.extensionLike("po")) {
|
||||
BlockDevice blockDevice = new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE);
|
||||
poDevice = new BlockToTrackSectorAdapter(blockDevice, new ProdosBlockToTrackSectorAdapterStrategy());
|
||||
}
|
||||
else {
|
||||
doDevice = new DosOrderedTrackSectorDevice(ctx.source, Hint.DOS_SECTOR_ORDER);
|
||||
BlockDevice blockDevice = new ProdosOrderedBlockDevice(ctx.source, BlockDevice.STANDARD_BLOCK_SIZE);
|
||||
poDevice = new BlockToTrackSectorAdapter(blockDevice, new ProdosBlockToTrackSectorAdapterStrategy());
|
||||
}
|
||||
switch (hint) {
|
||||
case DOS_SECTOR_ORDER -> {
|
||||
if (doDevice != null) {
|
||||
devices.add(doDevice);
|
||||
}
|
||||
if (poDevice != null) {
|
||||
devices.add(poDevice);
|
||||
}
|
||||
}
|
||||
case NIBBLE_SECTOR_ORDER -> {
|
||||
if (doDevice != null) {
|
||||
devices.add(SkewedTrackSectorDevice.dosToPhysicalSkew(doDevice));
|
||||
}
|
||||
if (poDevice != null) {
|
||||
devices.add(SkewedTrackSectorDevice.dosToPhysicalSkew(poDevice));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public List<TrackSectorDevice> get() {
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user