Now identifying non-standard disk formatting (limited to non-standard nibble images and DOS 3.x).

This commit is contained in:
Rob Greene
2025-09-06 14:41:15 -05:00
parent 48a17e8a93
commit a89616ef16
5 changed files with 63 additions and 22 deletions

View File

@@ -75,8 +75,21 @@ public class DosDiskFactory implements DiskFactory {
// ... and then test for DOS VTOC etc. Passing track number along to hopefully handle it later!
for (TrackSectorDevice device : devices) {
if (check(device)) {
ctx.disks.add(new DosFormatDisk(ctx.source.getName(), device));
if (device.is(Hint.NONSTANDARD_NIBBLE_IMAGE)) {
// The assumption is that we need to scan (and keep scanning) for possible DOS catalogs...
for (int catalogTrack = 3; catalogTrack < device.getGeometry().tracksOnDisk(); catalogTrack++) {
try {
if (check(device, catalogTrack)) {
ctx.disks.add(new DosFormatDisk(ctx.source.getName(), device, catalogTrack));
}
} catch (Throwable t) {
// ignored. Sort of expected.
}
}
}
// ... otherwise, just do the assumed track 17 check!
else if (check(device, CATALOG_TRACK)) {
ctx.disks.add(new DosFormatDisk(ctx.source.getName(), device, CATALOG_TRACK));
}
}
}
@@ -84,8 +97,8 @@ public class DosDiskFactory implements DiskFactory {
/**
* Test this image order by looking for a likely DOS VTOC and set of catalog sectors.
*/
public boolean check(TrackSectorDevice device) {
DataBuffer vtoc = device.readSector(CATALOG_TRACK, VTOC_SECTOR);
public boolean check(TrackSectorDevice device, final int catalogTrack) {
DataBuffer vtoc = device.readSector(catalogTrack, VTOC_SECTOR);
int nextTrack = vtoc.getUnsignedByte(0x01);
int nextSector = vtoc.getUnsignedByte(0x02);
int tracksPerDisk = vtoc.getUnsignedByte(0x34);
@@ -96,13 +109,13 @@ public class DosDiskFactory implements DiskFactory {
}
if (nextSector != 0 && nextTrack == 0) {
// Some folks zeroed out the next track field, so try the same as VTOC (T17)
nextTrack = DosFormatDisk.CATALOG_TRACK;
nextTrack = catalogTrack;
}
// Start with VTOC test
boolean good = nextTrack <= tracksPerDisk // expect catalog to be sensible
&& nextSector > 0 // expect catalog to be...
&& nextSector < sectorsPerTrack // ... a legitimate sector
&& tracksPerDisk >= CATALOG_TRACK // expect sensible...
&& tracksPerDisk >= catalogTrack // expect sensible...
&& tracksPerDisk <= 50 // ... tracks per disk
&& sectorsPerTrack > 10 // expect sensible...
&& sectorsPerTrack <= 32; // ... sectors per disk

View File

@@ -120,14 +120,16 @@ public class DosFormatDisk extends FormattedDisk {
}
}
private TrackSectorDevice device;
private final TrackSectorDevice device;
private final int catalogTrack;
/**
* Constructor for DosFormatDisk.
*/
public DosFormatDisk(String filename, TrackSectorDevice device) {
public DosFormatDisk(String filename, TrackSectorDevice device, int catalogTrack) {
super(filename, device.get(Source.class).orElseThrow());
this.device = device;
this.catalogTrack = catalogTrack;
}
@Override
@@ -140,7 +142,7 @@ public class DosFormatDisk extends FormattedDisk {
* be 140K in size.
*/
public static DosFormatDisk[] create(String filename, TrackSectorDevice device) {
DosFormatDisk disk = new DosFormatDisk(filename, device);
DosFormatDisk disk = new DosFormatDisk(filename, device, CATALOG_TRACK);
disk.format();
return new DosFormatDisk[] { disk };
}
@@ -152,9 +154,9 @@ public class DosFormatDisk extends FormattedDisk {
public static DosFormatDisk[] create(String filename, BlockDevice device, TrackSectorToBlockStrategy... strategies) {
assert strategies.length == 2;
assert device.getGeometry().blocksOnDevice() == 1600;
DosFormatDisk disk1 = new DosFormatDisk(filename, new BlockToTrackSectorAdapter(device, strategies[0]));
DosFormatDisk disk1 = new DosFormatDisk(filename, new BlockToTrackSectorAdapter(device, strategies[0]), CATALOG_TRACK);
disk1.format();
DosFormatDisk disk2 = new DosFormatDisk(filename, new BlockToTrackSectorAdapter(device, strategies[1]));
DosFormatDisk disk2 = new DosFormatDisk(filename, new BlockToTrackSectorAdapter(device, strategies[1]), CATALOG_TRACK);
disk2.format();
return new DosFormatDisk[] { disk1, disk2 };
}
@@ -186,7 +188,7 @@ public class DosFormatDisk extends FormattedDisk {
}
if (sector != 0 && track == 0) {
// Some folks zeroed out the next track field, so try the same as VTOC (T17)
track = CATALOG_TRACK;
track = catalogTrack;
}
final Set<DosSectorAddress> visits = new HashSet<>();
while (sector != 0) { // bug fix: iterate through all catalog _sectors_
@@ -320,14 +322,14 @@ public class DosFormatDisk extends FormattedDisk {
* Return the VTOC (Volume Table Of Contents).
*/
public byte[] readVtoc() {
return readSector(CATALOG_TRACK, VTOC_SECTOR);
return readSector(catalogTrack, VTOC_SECTOR);
}
/**
* Save the VTOC (Volume Table Of Contents) to disk.
*/
public void writeVtoc(byte[] vtoc) {
writeSector(CATALOG_TRACK, VTOC_SECTOR, vtoc);
writeSector(catalogTrack, VTOC_SECTOR, vtoc);
}
/**
@@ -392,6 +394,9 @@ public class DosFormatDisk extends FormattedDisk {
list.add(new DiskInformation(textBundle.get("DosFormatDisk.UsedSectors"), getUsedSectors())); //$NON-NLS-1$
list.add(new DiskInformation(textBundle.get("DosFormatDisk.TracksOnDisk"), getTracks())); //$NON-NLS-1$
list.add(new DiskInformation(textBundle.get("DosFormatDisk.SectorsOnDisk"), getSectors())); //$NON-NLS-1$
if (catalogTrack != CATALOG_TRACK) {
list.add(new DiskInformation("Catalog Track (non-standard)", catalogTrack));
}
return list;
}
@@ -645,28 +650,28 @@ public class DosFormatDisk extends FormattedDisk {
byte[] data = new byte[SECTOR_SIZE];
for (int sector=firstCatalogSector; sector > 0; sector--) {
if (sector > 1) {
data[0x01] = CATALOG_TRACK;
data[0x01] = (byte)catalogTrack;
data[0x02] = (byte)(sector-1);
} else {
data[0x01] = 0;
data[0x02] = 0;
}
writeSector(CATALOG_TRACK, sector, data);
writeSector(catalogTrack, sector, data);
}
// create VTOC
data[0x01] = CATALOG_TRACK; // track# of first catalog sector
data[0x01] = (byte)catalogTrack; // track# of first catalog sector
data[0x02] = (byte)firstCatalogSector; // sector# of first catalog sector
data[0x03] = 3; // DOS 3.3 formatted
data[0x06] = (byte)254; // DISK VOLUME#
data[0x27] = TRACK_SECTOR_PAIRS; // maximum # of T/S pairs in a sector
data[0x30] = CATALOG_TRACK+1; // last track where sectors allocated
data[0x30] = (byte)(catalogTrack+1); // last track where sectors allocated
data[0x31] = 1; // direction of allocation
data[0x34] = (byte)tracksPerDisk; // tracks per disk
data[0x35] = (byte)sectorsPerTrack; // sectors per track
data[0x37] = 1; // 36/37 are # of bytes per sector
for (int track=0; track<tracksPerDisk; track++) {
for (int sector=0; sector<sectorsPerTrack; sector++) {
if (track == 0 || track == CATALOG_TRACK) {
if (track == 0 || track == catalogTrack) {
setSectorUsed(track, sector, data);
} else {
setSectorFree(track, sector, data);

View File

@@ -31,6 +31,7 @@ import static org.applecommander.device.nibble.NibbleUtil.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class TrackSectorNibbleDevice implements TrackSectorDevice {
/**
@@ -121,6 +122,7 @@ public class TrackSectorNibbleDevice implements TrackSectorDevice {
private final DiskMarker[] diskMarkers;
private final NibbleDiskCodec dataCodec;
private final Geometry geometry;
private final Set<Hint> hints;
private TrackSectorNibbleDevice(NibbleTrackReaderWriter trackReaderWriter, NibbleDiskCodec dataCodec,
int sectorsPerTrack, DiskMarker... diskMarkers) {
@@ -128,6 +130,9 @@ public class TrackSectorNibbleDevice implements TrackSectorDevice {
this.diskMarkers = diskMarkers;
this.dataCodec = dataCodec;
this.geometry = new Geometry(trackReaderWriter.getTracksOnDevice(), sectorsPerTrack);
this.hints = diskMarkers.length == 1
? Set.of(Hint.NIBBLE_SECTOR_ORDER)
: Set.of(Hint.NIBBLE_SECTOR_ORDER, Hint.NONSTANDARD_NIBBLE_IMAGE);
}
@Override
@@ -137,7 +142,7 @@ public class TrackSectorNibbleDevice implements TrackSectorDevice {
@Override
public boolean is(Hint hint) {
return hint == Hint.NIBBLE_SECTOR_ORDER;
return hints.contains(hint);
}
@Override

View File

@@ -19,11 +19,29 @@
*/
package org.applecommander.hint;
/**
* Helpful hints that indicate something "interesting" (to code at least) about this <em>thing</em>.
* @see HintProvider
*/
public enum Hint {
/** "Nibble" sector order is really physical sector order. */
NIBBLE_SECTOR_ORDER,
/** Sectors are in DOS 3.3 sector order. */
DOS_SECTOR_ORDER,
/**
* Sectors are organized in ProDOS sector order. Typically, this is initially read as a ProDOS block
* and (if needed), mapped back to DOS tracks and sectors.
*/
PRODOS_BLOCK_ORDER,
/** Temporary flag to indicate this image was automagically extracted from a SHK or SDK image. */
ORIGIN_SHRINKIT,
/** Origin for this image was a 2IMG image. */
UNIVERSAL_DISK_IMAGE,
DISK_COPY_IMAGE
/** Origin for this image was a DiskCopy image. */
DISK_COPY_IMAGE,
/**
* This flag is used to indicate a protected disk. Meaning factories may need to search a bit more
* for disk markers.
*/
NONSTANDARD_NIBBLE_IMAGE
}

View File

@@ -1826,7 +1826,7 @@ public class DiskExplorerTab {
BlockDevice blockDevice = new TrackSectorToBlockAdapter(targetDevice, TrackSectorToBlockAdapter.BlockStyle.CPM);
yield new CpmFormatDisk(filename, blockDevice);
}
case DosFormatDisk ignored -> new DosFormatDisk(filename, targetDevice);
case DosFormatDisk ignored -> new DosFormatDisk(filename, targetDevice, DosFormatDisk.CATALOG_TRACK);
case GutenbergFormatDisk ignored -> new GutenbergFormatDisk(filename, targetDevice);
case NakedosFormatDisk ignored -> new NakedosFormatDisk(filename, targetDevice);
case PascalFormatDisk ignored -> {