mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2025-02-06 06:30:20 +00:00
Updating to allow order to be specified in create. #61
This commit is contained in:
parent
53c860f102
commit
eb83281795
@ -88,6 +88,7 @@ public class Main {
|
||||
public static void main(String[] args) {
|
||||
CommandLine cmd = new CommandLine(new Main());
|
||||
cmd.setExecutionExceptionHandler(new PrintExceptionMessageHandler());
|
||||
cmd.setCaseInsensitiveEnumValuesAllowed(true);
|
||||
if (args.length == 0) {
|
||||
cmd.usage(System.out);
|
||||
System.exit(1);
|
||||
|
@ -0,0 +1,83 @@
|
||||
package io.github.applecommander.acx;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.webcodepro.applecommander.storage.Disk;
|
||||
import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout;
|
||||
import com.webcodepro.applecommander.storage.physical.DosOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ImageOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.NibbleOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ProdosOrder;
|
||||
|
||||
public enum OrderType {
|
||||
DOS(OrderType::createDosImageOrder),
|
||||
NIBBLE(OrderType::create140kNibbleImageOrder),
|
||||
PRODOS(OrderType::createProdosImageOrder);
|
||||
|
||||
private static Logger LOG = Logger.getLogger(OrderType.class.getName());
|
||||
|
||||
private Function<Integer,ImageOrder> createImageOrderFn;
|
||||
|
||||
private OrderType(Function<Integer,ImageOrder> createImageOrderFn) {
|
||||
this.createImageOrderFn = createImageOrderFn;
|
||||
}
|
||||
|
||||
public ImageOrder createImageOrder(int size) {
|
||||
return createImageOrderFn.apply(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* At this time, the various DOS disks only support 140K or 800K disks and
|
||||
* we have to rely on the SystemType to actually evaluate the correct size.
|
||||
*/
|
||||
static ImageOrder createDosImageOrder(int size) {
|
||||
if (size < Disk.APPLE_140KB_DISK) {
|
||||
LOG.warning("Setting image size to 140KB.");
|
||||
size = Disk.APPLE_140KB_DISK;
|
||||
}
|
||||
else if (size == Disk.APPLE_140KB_DISK) {
|
||||
// Size is valid; don't warn and don't bump to 800K.
|
||||
}
|
||||
else if (size != Disk.APPLE_800KB_DISK) {
|
||||
LOG.warning("Setting image size to 800KB.");
|
||||
size = Disk.APPLE_800KB_DISK;
|
||||
}
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[size]);
|
||||
return new DosOrder(layout);
|
||||
}
|
||||
/**
|
||||
* Nibblized disks are always 140K disks (or ~230K on disk).
|
||||
*/
|
||||
static ImageOrder create140kNibbleImageOrder(int size) {
|
||||
if (size != Disk.APPLE_140KB_NIBBLE_DISK && size != Disk.APPLE_140KB_DISK) {
|
||||
LOG.warning("Setting image size to 140KB");
|
||||
}
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[Disk.APPLE_140KB_NIBBLE_DISK]);
|
||||
return new NibbleOrder(layout);
|
||||
}
|
||||
/**
|
||||
* Lock ProDOS into 140K, 800K, or anything between 800K and 32M.
|
||||
* This means you _could_ setup a 807KB disk if you wanted.
|
||||
*/
|
||||
static ImageOrder createProdosImageOrder(int size) {
|
||||
if (size < Disk.APPLE_140KB_DISK) {
|
||||
LOG.warning("Setting image size to 140KB.");
|
||||
size = Disk.APPLE_140KB_DISK;
|
||||
}
|
||||
else if (size == Disk.APPLE_140KB_DISK) {
|
||||
// Size is valid; don't warn and don't bump to 800K.
|
||||
}
|
||||
else if (size < Disk.APPLE_800KB_DISK) {
|
||||
LOG.warning("Setting image size to 800KB.");
|
||||
size = Disk.APPLE_800KB_DISK;
|
||||
}
|
||||
else if (size > Disk.APPLE_32MB_HARDDISK) {
|
||||
LOG.warning("Setting image size to 32MB.");
|
||||
size = Disk.APPLE_32MB_HARDDISK;
|
||||
}
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(size);
|
||||
return new ProdosOrder(layout);
|
||||
}
|
||||
|
||||
}
|
@ -5,60 +5,79 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.webcodepro.applecommander.storage.Disk;
|
||||
import com.webcodepro.applecommander.storage.DiskException;
|
||||
import com.webcodepro.applecommander.storage.FileEntry;
|
||||
import com.webcodepro.applecommander.storage.FormattedDisk;
|
||||
import com.webcodepro.applecommander.storage.os.dos33.DosFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout;
|
||||
import com.webcodepro.applecommander.storage.physical.DosOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ImageOrder;
|
||||
import com.webcodepro.applecommander.storage.physical.ProdosOrder;
|
||||
|
||||
import io.github.applecommander.acx.converter.DataSizeConverter;
|
||||
import io.github.applecommander.acx.fileutil.FileUtils;
|
||||
|
||||
public enum SystemType {
|
||||
DOS(SystemType::createDosImageOrder, SystemType::copyDosSystemTracks),
|
||||
OZDOS(SystemType::create800kDosImageOrder, SystemType::copyDosSystemTracks),
|
||||
UNIDOS(SystemType::create800kDosImageOrder, SystemType::copyDosSystemTracks),
|
||||
PRODOS(SystemType::createProdosImageOrder, SystemType::copyProdosSystemFiles),
|
||||
PASCAL(SystemType::createProdosImageOrder, SystemType::copyPascalSystemFiles);
|
||||
DOS(OrderType.DOS, SystemType::enforce140KbDisk,
|
||||
SystemType::copyDosSystemTracks),
|
||||
// OzdosFormatDisk is structured on top of ProDOS blocks in the implementation.
|
||||
OZDOS(OrderType.PRODOS, SystemType::enforce800KbDisk,
|
||||
SystemType::copyDosSystemTracks),
|
||||
// UnidosFormatDisk is structured on top of DOS track/sectors in the implementation.
|
||||
UNIDOS(OrderType.DOS, SystemType::enforce800KbDisk,
|
||||
SystemType::copyDosSystemTracks),
|
||||
PRODOS(OrderType.PRODOS, SystemType::enforce140KbOr800KbUpTo32MbDisk,
|
||||
SystemType::copyProdosSystemFiles),
|
||||
PASCAL(OrderType.PRODOS, SystemType::enforce140KbDisk,
|
||||
SystemType::copyPascalSystemFiles);
|
||||
|
||||
private static Logger LOG = Logger.getLogger(SystemType.class.getName());
|
||||
static Logger LOG = Logger.getLogger(SystemType.class.getName());
|
||||
|
||||
private Function<Integer,ImageOrder> createImageOrderFn;
|
||||
private OrderType defaultOrderType;
|
||||
private Function<Integer,Integer> enforceDiskSizeFn;
|
||||
private BiConsumer<FormattedDisk,FormattedDisk> copySystemFn;
|
||||
|
||||
private SystemType(Function<Integer,ImageOrder> createImageOrderFn,
|
||||
BiConsumer<FormattedDisk,FormattedDisk> copySystemFn) {
|
||||
this.createImageOrderFn = createImageOrderFn;
|
||||
private SystemType(OrderType defaultOrderType,
|
||||
Function<Integer,Integer> enforceDiskSizeFn,
|
||||
BiConsumer<FormattedDisk,FormattedDisk> copySystemFn) {
|
||||
this.defaultOrderType = defaultOrderType;
|
||||
this.enforceDiskSizeFn = enforceDiskSizeFn;
|
||||
this.copySystemFn = copySystemFn;
|
||||
}
|
||||
|
||||
public ImageOrder createImageOrder(int size) {
|
||||
return createImageOrderFn.apply(size);
|
||||
public OrderType defaultOrderType() {
|
||||
return defaultOrderType;
|
||||
}
|
||||
public int validateSize(int size) {
|
||||
return enforceDiskSizeFn.apply(size);
|
||||
}
|
||||
public void copySystem(FormattedDisk target, FormattedDisk source) {
|
||||
copySystemFn.accept(target, source);
|
||||
}
|
||||
|
||||
private static ImageOrder createDosImageOrder(int size) {
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[size]);
|
||||
return new DosOrder(layout);
|
||||
}
|
||||
private static ImageOrder create800kDosImageOrder(int size) {
|
||||
if (size != 800 * DataSizeConverter.KB) {
|
||||
LOG.warning("Setting image size to 800KB.");
|
||||
}
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(new byte[800 * DataSizeConverter.KB]);
|
||||
return new DosOrder(layout);
|
||||
}
|
||||
private static ImageOrder createProdosImageOrder(int size) {
|
||||
ByteArrayImageLayout layout = new ByteArrayImageLayout(size);
|
||||
return new ProdosOrder(layout);
|
||||
}
|
||||
|
||||
private static void copyDosSystemTracks(FormattedDisk targetDisk, FormattedDisk source) {
|
||||
static int enforce140KbDisk(int size) {
|
||||
if (size != Disk.APPLE_140KB_DISK) {
|
||||
LOG.warning("Setting image size to 140KB");
|
||||
}
|
||||
return Disk.APPLE_140KB_DISK;
|
||||
}
|
||||
static int enforce800KbDisk(int size) {
|
||||
if (size != Disk.APPLE_800KB_DISK) {
|
||||
LOG.warning("Setting image size to 800KB.");
|
||||
}
|
||||
return Disk.APPLE_800KB_DISK;
|
||||
}
|
||||
static int enforce140KbOr800KbUpTo32MbDisk(int size) {
|
||||
if (size <= Disk.APPLE_140KB_DISK) {
|
||||
return enforce140KbDisk(size);
|
||||
}
|
||||
if (size <= Disk.APPLE_800KB_DISK) {
|
||||
return enforce800KbDisk(size);
|
||||
}
|
||||
if (size > Disk.APPLE_32MB_HARDDISK) {
|
||||
LOG.warning("Setting image size to 32MB.");
|
||||
return Disk.APPLE_32MB_HARDDISK;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void copyDosSystemTracks(FormattedDisk targetDisk, FormattedDisk source) {
|
||||
DosFormatDisk target = (DosFormatDisk)targetDisk;
|
||||
// FIXME messing with the VTOC should be handled elsewhere
|
||||
byte[] vtoc = source.readSector(DosFormatDisk.CATALOG_TRACK, DosFormatDisk.VTOC_SECTOR);
|
||||
@ -71,7 +90,7 @@ public enum SystemType {
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void copyProdosSystemFiles(FormattedDisk target, FormattedDisk source) {
|
||||
static void copyProdosSystemFiles(FormattedDisk target, FormattedDisk source) {
|
||||
// We need to explicitly fix the boot block
|
||||
target.writeBlock(0, source.readBlock(0));
|
||||
target.writeBlock(1, source.readBlock(1));
|
||||
@ -86,7 +105,7 @@ public enum SystemType {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
private static void copyPascalSystemFiles(FormattedDisk target, FormattedDisk source) {
|
||||
static void copyPascalSystemFiles(FormattedDisk target, FormattedDisk source) {
|
||||
// We need to explicitly fix the boot block
|
||||
target.writeBlock(0, source.readBlock(0));
|
||||
target.writeBlock(1, source.readBlock(1));
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.applecommander.acx.command;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.webcodepro.applecommander.storage.Disk;
|
||||
@ -11,10 +12,11 @@ import com.webcodepro.applecommander.storage.os.pascal.PascalFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk;
|
||||
import com.webcodepro.applecommander.storage.physical.ImageOrder;
|
||||
|
||||
import io.github.applecommander.acx.OrderType;
|
||||
import io.github.applecommander.acx.SystemType;
|
||||
import io.github.applecommander.acx.base.ReusableCommandOptions;
|
||||
import io.github.applecommander.acx.converter.DataSizeConverter;
|
||||
import io.github.applecommander.acx.converter.SystemTypeConverter;
|
||||
import picocli.CommandLine.ArgGroup;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@ -27,12 +29,14 @@ public class CreateDiskCommand extends ReusableCommandOptions {
|
||||
defaultValue = "${ACX_DISK_NAME}")
|
||||
private String imageName;
|
||||
|
||||
@Option(names = { "-t", "--type" }, required = true, converter = SystemTypeConverter.class,
|
||||
description = "Select system type (DOS, ProDOS, Pascal.")
|
||||
private SystemType type;
|
||||
@ArgGroup(multiplicity = "1", heading = "%nOperating System Selection:%n")
|
||||
private SystemSelection systemSelection;
|
||||
|
||||
@ArgGroup(heading = "%nDisk Sector Ordering Selection:%n")
|
||||
private OrderSelection orderSelection = new OrderSelection();
|
||||
|
||||
@Option(names = { "-s", "--size" }, defaultValue = "140kb", converter = DataSizeConverter.class,
|
||||
description = "Select disk size (140K, 800K, 10M).")
|
||||
description = "Select disk size (examples: 140K, 800K, 10M).")
|
||||
private int size;
|
||||
|
||||
@Option(names = { "-f", "--format" },
|
||||
@ -45,11 +49,20 @@ public class CreateDiskCommand extends ReusableCommandOptions {
|
||||
|
||||
@Override
|
||||
public int handleCommand() throws Exception {
|
||||
LOG.info(() -> String.format("Creating %s image of type %s.", DataSizeConverter.format(size), type));
|
||||
SystemType systemType = systemSelection.get();
|
||||
|
||||
ImageOrder order = type.createImageOrder(size);
|
||||
// This allows a defaulted OrderType to be adjusted based on SystemType.
|
||||
OrderType actualOrderType = orderSelection.get().orElse(systemType.defaultOrderType());
|
||||
|
||||
// Size is constrained in DOS and Pascal
|
||||
int correctedSize = systemType.validateSize(size);
|
||||
|
||||
LOG.info(() -> String.format("Creating %s image of type %s (%s).",
|
||||
DataSizeConverter.format(correctedSize), systemType, actualOrderType));
|
||||
|
||||
ImageOrder order = actualOrderType.createImageOrder(correctedSize);
|
||||
FormattedDisk[] disks = null;
|
||||
switch (type) {
|
||||
switch (systemType) {
|
||||
case DOS:
|
||||
disks = DosFormatDisk.create(imageName, order);
|
||||
break;
|
||||
@ -69,11 +82,61 @@ public class CreateDiskCommand extends ReusableCommandOptions {
|
||||
|
||||
if (formatSource != null) {
|
||||
Disk systemSource = new Disk(formatSource);
|
||||
type.copySystem(disks[0], systemSource.getFormattedDisks()[0]);
|
||||
systemType.copySystem(disks[0], systemSource.getFormattedDisks()[0]);
|
||||
}
|
||||
|
||||
saveDisk(disks[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static class SystemSelection {
|
||||
private SystemType systemType;
|
||||
|
||||
public SystemType get() {
|
||||
return systemType;
|
||||
}
|
||||
|
||||
@Option(names = "--dos", description = "DOS formatted disk.")
|
||||
public void selectDos(boolean flag) {
|
||||
systemType = SystemType.DOS;
|
||||
}
|
||||
@Option(names = "--ozdos", description = "OzDOS 800K formatted disk.")
|
||||
public void selectOzdos(boolean flag) {
|
||||
systemType = SystemType.OZDOS;
|
||||
}
|
||||
@Option(names = "--unidos", description = "UniDOS 800K formatted disk.")
|
||||
public void selectUnidos(boolean flag) {
|
||||
systemType = SystemType.UNIDOS;
|
||||
}
|
||||
@Option(names = "--pascal", description = "Pascal formatted disk.")
|
||||
public void selectPascal(boolean flag) {
|
||||
systemType = SystemType.PASCAL;
|
||||
}
|
||||
@Option(names = "--prodos", description = "ProDOS formatted disk.")
|
||||
public void selectProdos(boolean flag) {
|
||||
systemType = SystemType.PRODOS;
|
||||
}
|
||||
}
|
||||
|
||||
private static class OrderSelection {
|
||||
private Optional<OrderType> orderType = Optional.empty();
|
||||
|
||||
public Optional<OrderType> get() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
@Option(names = { "--dos-order" }, description = "DOS ordered sectors.")
|
||||
public void selectDosOrder(boolean flag) {
|
||||
orderType = Optional.of(OrderType.DOS);
|
||||
}
|
||||
@Option(names = { "--nibble-order" }, description = "DOS ordered, nibble encoded sectors.")
|
||||
public void selectNibbleOrder(boolean flag) {
|
||||
orderType = Optional.of(OrderType.NIBBLE);
|
||||
}
|
||||
@Option(names = { "--prodos-order" }, description = "ProDOS ordered sectors/blocks.")
|
||||
public void selectProdosOrder(boolean flag) {
|
||||
orderType = Optional.of(OrderType.PRODOS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package io.github.applecommander.acx;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.webcodepro.applecommander.storage.Disk;
|
||||
|
||||
public class OrderTypeTest {
|
||||
@Test
|
||||
public void testCreateDosImageOrder() {
|
||||
assertEquals(Disk.APPLE_140KB_DISK, OrderType.createDosImageOrder(0).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_140KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_800KB_DISK).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK, OrderType.createDosImageOrder(Disk.APPLE_800KB_DISK+1).getPhysicalSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate140kNibbleImageOrder() {
|
||||
assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(0).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_140KB_NIBBLE_DISK, OrderType.create140kNibbleImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateProdosImageOrder() {
|
||||
assertEquals(Disk.APPLE_140KB_DISK, OrderType.createProdosImageOrder(0).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_140KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_140KB_DISK).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_140KB_DISK+1).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK, OrderType.createProdosImageOrder(Disk.APPLE_800KB_DISK).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_800KB_DISK+1, OrderType.createProdosImageOrder(Disk.APPLE_800KB_DISK+1).getPhysicalSize());
|
||||
assertEquals(Disk.APPLE_10MB_HARDDISK, OrderType.createProdosImageOrder(Disk.APPLE_10MB_HARDDISK).getPhysicalSize());
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.github.applecommander.acx;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import com.webcodepro.applecommander.storage.Disk;
|
||||
|
||||
public class SystemTypeTest {
|
||||
@Test
|
||||
public void testEnforce140KbDisk() {
|
||||
assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(0));
|
||||
assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(Disk.APPLE_140KB_DISK));
|
||||
assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbDisk(Disk.APPLE_800KB_DISK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnforce800KbDisk() {
|
||||
assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(0));
|
||||
assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(Disk.APPLE_800KB_DISK));
|
||||
assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce800KbDisk(Disk.APPLE_32MB_HARDDISK));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnforce140KbOr800KbUpTo32MbDisk() {
|
||||
assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(0));
|
||||
assertEquals(Disk.APPLE_140KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_140KB_DISK));
|
||||
assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_140KB_DISK+1));
|
||||
assertEquals(Disk.APPLE_800KB_DISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_800KB_DISK));
|
||||
assertEquals(Disk.APPLE_800KB_DISK+1, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_800KB_DISK+1));
|
||||
assertEquals(Disk.APPLE_32MB_HARDDISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Disk.APPLE_32MB_HARDDISK));
|
||||
assertEquals(Disk.APPLE_32MB_HARDDISK, SystemType.enforce140KbOr800KbUpTo32MbDisk(Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user