diff --git a/lib/ac-api/src/main/java/org/applecommander/device/TrackSectorDevice.java b/lib/ac-api/src/main/java/org/applecommander/device/TrackSectorDevice.java index 3ac36f8c..d5e817b7 100644 --- a/lib/ac-api/src/main/java/org/applecommander/device/TrackSectorDevice.java +++ b/lib/ac-api/src/main/java/org/applecommander/device/TrackSectorDevice.java @@ -19,6 +19,7 @@ */ package org.applecommander.device; +import org.applecommander.device.Coordinate.TrackAndSectorCoordinate; import org.applecommander.util.DataBuffer; import org.applecommander.util.InformationGroup; import org.applecommander.util.InformationProvider; @@ -102,6 +103,12 @@ public interface TrackSectorDevice extends Device { public int deviceSize() { return sectorsPerDisk() * SECTOR_SIZE; } + public int calculateSectorOffset(int track, int sector) { + return track * sectorsPerTrack + sector; + } + public TrackAndSectorCoordinate sectorOffsetToCoordinate(int sectorOffset) { + return new TrackAndSectorCoordinate(sectorOffset / sectorsPerTrack, sectorOffset % sectorsPerTrack); + } @Override public List information() { diff --git a/lib/ac-api/src/main/java/org/applecommander/os/SequentialAllocator.java b/lib/ac-api/src/main/java/org/applecommander/os/SequentialAllocator.java new file mode 100644 index 00000000..4d5fdbee --- /dev/null +++ b/lib/ac-api/src/main/java/org/applecommander/os/SequentialAllocator.java @@ -0,0 +1,51 @@ +package org.applecommander.os; + +import org.applecommander.util.Range; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/// The SequentialAllocator is intended to handle what is, essentially, a +/// single dimension allocation. That is, if the disk is allocated by sequential +/// chunks, this allocator should support it. For images that use T/S geometry +/// instead of block geometry, the T/S will need to be transformed. +/// +/// For instance, GameDOS allocates by T/S but allocates all in a chunk. So once +/// there is a starting place, the rest of the file follows in a very specific +/// order. +public class SequentialAllocator { + private final int totalSize; + private final List used = new ArrayList<>(); + + public SequentialAllocator(int totalSize) { + this.totalSize = totalSize; + } + + public void addUsed(int first, int last) { + assert first <= last; + assert first < totalSize && last <= totalSize; + used.add(new Range(first, last)); + } + public void addUsedByLength(int first, int length) { + addUsed(first, first+length-1); + } + + /// Look for `requestSize` spaces between the used ranges. + /// Returns either the first placement that the request will fit + /// or a `-1` if there is no fit. + public int find(int requestSize) { + used.sort(Comparator.comparingInt(Range::first)); + int start = 0; + for (Range range : used) { + if (range.first() - start >= requestSize) { + return start; + } + start = range.last() + 1; + } + if (totalSize - start >= requestSize) { + return start; + } + return -1; + } +} diff --git a/lib/ac-api/src/test/java/org/applecommander/os/SequentialAllocatorTest.java b/lib/ac-api/src/test/java/org/applecommander/os/SequentialAllocatorTest.java new file mode 100644 index 00000000..4888c2f8 --- /dev/null +++ b/lib/ac-api/src/test/java/org/applecommander/os/SequentialAllocatorTest.java @@ -0,0 +1,21 @@ +package org.applecommander.os; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SequentialAllocatorTest { + @Test + public void test() { + SequentialAllocator allocator = new SequentialAllocator(10); + allocator.addUsed(2,4); + allocator.addUsed(5,6); + + // Allocation: + // 0123456789 + // FFUUUUUFFF + assertEquals(0, allocator.find(2)); + assertEquals(7, allocator.find(3)); + assertEquals(-1, allocator.find(4)); + } +}