From a89616ef16903b2b84fd46e770bf79d4c1fed5b4 Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Sat, 6 Sep 2025 14:41:15 -0500 Subject: [PATCH] Now identifying non-standard disk formatting (limited to non-standard nibble images and DOS 3.x). --- .../storage/os/dos33/DosDiskFactory.java | 25 +++++++++++---- .../storage/os/dos33/DosFormatDisk.java | 31 +++++++++++-------- .../device/TrackSectorNibbleDevice.java | 7 ++++- .../java/org/applecommander/hint/Hint.java | 20 +++++++++++- .../ui/swt/DiskExplorerTab.java | 2 +- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosDiskFactory.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosDiskFactory.java index f14dc990..9df18965 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosDiskFactory.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosDiskFactory.java @@ -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 diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java index c1972144..6dbdd195 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java @@ -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 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 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 diff --git a/lib/ac-api/src/main/java/org/applecommander/hint/Hint.java b/lib/ac-api/src/main/java/org/applecommander/hint/Hint.java index cc80d3c7..22702964 100644 --- a/lib/ac-api/src/main/java/org/applecommander/hint/Hint.java +++ b/lib/ac-api/src/main/java/org/applecommander/hint/Hint.java @@ -19,11 +19,29 @@ */ package org.applecommander.hint; +/** + * Helpful hints that indicate something "interesting" (to code at least) about this thing. + * @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 } diff --git a/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/DiskExplorerTab.java b/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/DiskExplorerTab.java index c7bb065d..2fc6c1bf 100644 --- a/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/DiskExplorerTab.java +++ b/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/DiskExplorerTab.java @@ -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 -> {