mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2026-04-20 18:17:12 +00:00
Allowing nibble track dumps even if we don't recognize the disk.
This commit is contained in:
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2025 by Robert Greene and others
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package io.github.applecommander.acx.base;
|
||||
|
||||
import com.webcodepro.applecommander.storage.DiskFactory;
|
||||
import com.webcodepro.applecommander.storage.FormattedDisk;
|
||||
import io.github.applecommander.acx.converter.DiskFactoryContextConverter;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ReadOnlyDiskContextCommandOptions extends ReusableCommandOptions {
|
||||
@Option(names = { "-d", "--disk" }, description = "Image to process [$ACX_DISK_NAME].", required = true,
|
||||
converter = DiskFactoryContextConverter.class, defaultValue = "${ACX_DISK_NAME}")
|
||||
private DiskFactory.Context ctx;
|
||||
|
||||
@Option(names = { "-k", "--number" }, description = "Select disk number to access [$ACX_DISK_NUMBER].",
|
||||
defaultValue = "${ACX_DISK_NUMBER}")
|
||||
private Integer diskNumber;
|
||||
|
||||
protected List<FormattedDisk> selectedDisks() {
|
||||
if (diskNumber != null) {
|
||||
return List.of(ctx.disks.get(diskNumber));
|
||||
}
|
||||
return ctx.disks;
|
||||
}
|
||||
|
||||
protected DiskFactory.Context context() {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import com.webcodepro.applecommander.storage.TrackSectorDeviceAdapter;
|
||||
import com.webcodepro.applecommander.util.AppleUtil;
|
||||
|
||||
import com.webcodepro.applecommander.util.Range;
|
||||
import io.github.applecommander.acx.base.ReadOnlyDiskImageCommandOptions;
|
||||
import io.github.applecommander.acx.base.ReadOnlyDiskContextCommandOptions;
|
||||
import io.github.applecommander.acx.converter.IntegerTypeConverter;
|
||||
import io.github.applecommander.acx.converter.RangeTypeConverter;
|
||||
import io.github.applecommander.disassembler.api.Disassembler;
|
||||
@@ -49,7 +49,7 @@ import picocli.CommandLine.Mixin;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
@Command(name = "dump", description = "Dump a block or sector.", sortOptions = false)
|
||||
public class DumpCommand extends ReadOnlyDiskImageCommandOptions {
|
||||
public class DumpCommand extends ReadOnlyDiskContextCommandOptions {
|
||||
@ArgGroup(heading = "%nOutput Selection:%n")
|
||||
private OutputSelection output = new OutputSelection();
|
||||
|
||||
@@ -58,34 +58,37 @@ public class DumpCommand extends ReadOnlyDiskImageCommandOptions {
|
||||
|
||||
@Override
|
||||
public int handleCommand() throws Exception {
|
||||
FormattedDisk disk = selectedDisks().getFirst();
|
||||
if (options.coordinate.blockRangeSelection != null) {
|
||||
BlockDevice device = BlockDeviceAdapter.from(disk);
|
||||
options.coordinate.blockRangeSelection.blocks.stream().forEach(block -> {
|
||||
validateBlockNum(device, block);
|
||||
options.includesBootSector = block == 0;
|
||||
byte[] data = device.readBlock(block).asBytes();
|
||||
System.out.printf("Block #%d:\n", block);
|
||||
System.out.println(output.format(options, data));
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
else if (options.coordinate.trackSectorRangeSelection != null) {
|
||||
options.coordinate.trackSectorRangeSelection.tracks.stream().forEach(track -> {
|
||||
TrackSectorDevice device = TrackSectorDeviceAdapter.from(disk);
|
||||
options.coordinate.trackSectorRangeSelection.sectors.stream().forEach(sector -> {
|
||||
validateTrackAndSector(device, track, sector);
|
||||
options.includesBootSector = track == 0 && sector == 0;
|
||||
byte[] data = device.readSector(track, sector).asBytes();
|
||||
System.out.printf("Track %02d, Sector %02d:\n", track, sector);
|
||||
if (!selectedDisks().isEmpty()) {
|
||||
FormattedDisk disk = selectedDisks().getFirst();
|
||||
if (options.coordinate.blockRangeSelection != null) {
|
||||
BlockDevice device = BlockDeviceAdapter.from(disk);
|
||||
options.coordinate.blockRangeSelection.blocks.stream().forEach(block -> {
|
||||
validateBlockNum(device, block);
|
||||
options.includesBootSector = block == 0;
|
||||
byte[] data = device.readBlock(block).asBytes();
|
||||
System.out.printf("Block #%d:\n", block);
|
||||
System.out.println(output.format(options, data));
|
||||
});
|
||||
});
|
||||
return 0;
|
||||
return 0;
|
||||
} else if (options.coordinate.trackSectorRangeSelection != null) {
|
||||
options.coordinate.trackSectorRangeSelection.tracks.stream().forEach(track -> {
|
||||
TrackSectorDevice device = TrackSectorDeviceAdapter.from(disk);
|
||||
options.coordinate.trackSectorRangeSelection.sectors.stream().forEach(sector -> {
|
||||
validateTrackAndSector(device, track, sector);
|
||||
options.includesBootSector = track == 0 && sector == 0;
|
||||
byte[] data = device.readSector(track, sector).asBytes();
|
||||
System.out.printf("Track %02d, Sector %02d:\n", track, sector);
|
||||
System.out.println(output.format(options, data));
|
||||
});
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (options.coordinate.nibbleTrackRangeSelection != null) {
|
||||
NibbleTrackReaderWriter trackReaderWriter = disk.get(NibbleTrackReaderWriter.class)
|
||||
.orElseThrow(() -> new RuntimeException("This is not a nibble device."));
|
||||
if (context().nibbleTrackReaderWriter == null) {
|
||||
throw new RuntimeException("This is not a nibble device.");
|
||||
}
|
||||
NibbleTrackReaderWriter trackReaderWriter = context().nibbleTrackReaderWriter;
|
||||
options.coordinate.nibbleTrackRangeSelection.tracks.stream().forEach(track -> {
|
||||
final int tracksPerDisk = trackReaderWriter.getTracksOnDevice();
|
||||
if (track < 0 || track >= tracksPerDisk) {
|
||||
@@ -98,7 +101,13 @@ public class DumpCommand extends ReadOnlyDiskImageCommandOptions {
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
System.out.println("Please choose block(s) or track(s) and sector(s).");
|
||||
// detect errors since we might get here with an unrecognized disk
|
||||
if (options.coordinate.blockRangeSelection != null || options.coordinate.trackSectorRangeSelection != null) {
|
||||
System.out.println("Disk was not recognized.");
|
||||
}
|
||||
else {
|
||||
System.out.println("Please choose block(s) or track(s) and sector(s).");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* AppleCommander - An Apple ][ image utility.
|
||||
* Copyright (C) 2025 by Robert Greene and others
|
||||
* robgreene at users.sourceforge.net
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package io.github.applecommander.acx.converter;
|
||||
|
||||
import com.webcodepro.applecommander.storage.DiskFactory;
|
||||
import com.webcodepro.applecommander.storage.Disks;
|
||||
import org.applecommander.source.Source;
|
||||
import org.applecommander.source.Sources;
|
||||
import picocli.CommandLine.ITypeConverter;
|
||||
import picocli.CommandLine.TypeConversionException;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class DiskFactoryContextConverter implements ITypeConverter<DiskFactory.Context> {
|
||||
@Override
|
||||
public DiskFactory.Context convert(String filename) throws Exception {
|
||||
if (Files.exists(Path.of(filename))) {
|
||||
Source source = Sources.create(filename).orElseThrow();
|
||||
return Disks.inspect(source);
|
||||
}
|
||||
throw new TypeConversionException(String.format("Disk '%s' not found", filename));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user