26static constexpr uint8_t FLAG_SINGLE_SIDED = 0x10;
27static constexpr unsigned IDAM_FLAGS_MASK = 0xC000;
28static constexpr unsigned FLAG_MFM_SECTOR = 0x8000;
31[[nodiscard]]
static bool isValidDmkHeader(
const DmkHeader& header)
37 if (trackLen >= 0x4000)
return false;
38 if (trackLen <= 128)
return false;
39 if (header.
flags & ~0xd0)
return false;
46 , file(
std::move(file_))
50 file->read(std::span{&header, 1});
51 if (!isValidDmkHeader(header)) {
57 singleSided = (header.
flags & FLAG_SINGLE_SIDED) != 0;
66void DMKDiskImage::seekTrack(uint8_t track, uint8_t side)
68 size_t t = singleSided ? track : (2 * track + side);
69 file->seek(
sizeof(
DmkHeader) +
t * (dmkTrackLen + 128));
75 output.
clear(dmkTrackLen);
76 if ((singleSided && side) || (track >= numTracks)) {
81 seekTrack(track, side);
84 std::array<uint8_t, 2 * 64> idamBuf;
92 for (
auto i :
xrange(64)) {
93 unsigned idx = idamBuf[2 * i + 0] + 256 * idamBuf[2 * i + 1];
96 if ((idx & IDAM_FLAGS_MASK) != FLAG_MFM_SECTOR) {
100 idx &= ~IDAM_FLAGS_MASK;
107 if (idx >= dmkTrackLen) {
112 if (
int(idx) <= lastIdam) {
119 lastIdam = narrow<int>(idx);
126 if (singleSided && (side != 0)) {
131 if (numTracks <= track) [[unlikely]] {
132 extendImageToTrack(track);
134 doWriteTrack(track, side, input);
137void DMKDiskImage::doWriteTrack(uint8_t track, uint8_t side,
const RawTrack& input)
139 seekTrack(track, side);
142 std::array<uint8_t, 2 * 64> idamOut = {};
144 auto i :
xrange(std::min(64,
int(idamIn.size())))) {
145 auto t = (idamIn[i] + 128) | FLAG_MFM_SECTOR;
146 idamOut[2 * i + 0] = narrow<uint8_t>(
t & 0xff);
147 idamOut[2 * i + 1] = narrow<uint8_t>(
t >> 8);
149 file->write(idamOut);
152 assert(input.
getLength() == dmkTrackLen);
156void DMKDiskImage::extendImageToTrack(uint8_t track)
160 uint8_t numSides = singleSided ? 1 : 2;
161 while (numTracks <= track) {
162 for (
auto side :
xrange(numSides)) {
163 doWriteTrack(numTracks, side, emptyTrack);
170 std::array<uint8_t, 1> numTracksBuf = {numTracks};
171 file->write(numTracksBuf);
177 auto [track, side, sector] =
logToPhys(logicalSector);
192 auto [track, side, sector] =
logToPhys(logicalSector);
208 size_t t = singleSided ? numTracks : (2 * numTracks);
214 return writeProtected || file->isReadOnly();
222void DMKDiskImage::detectGeometryFallback()
Sha1Sum getSha1SumImpl(FilePool &filePool) override
DMKDiskImage(Filename filename, std::shared_ptr< File > file)
void readSectorImpl(size_t sector, SectorBuffer &buf) override
bool isWriteProtectedImpl() const override
void writeSectorImpl(size_t sector, const SectorBuffer &buf) override
size_t getNbSectorsImpl() const override
void readTrack(uint8_t track, uint8_t side, RawTrack &output) override
Read a full track from this disk image.
void writeTrackImpl(uint8_t track, uint8_t side, const RawTrack &input) override
unsigned getSectorsPerTrack()
void setNbSides(unsigned num)
void writeTrack(uint8_t track, uint8_t side, const RawTrack &input)
Replace a full track in this image with the given track.
void setSectorsPerTrack(unsigned num)
TSS logToPhys(size_t log)
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
This class represents a filename.
void addIdam(unsigned idx)
const auto & getIdamBuffer() const
std::optional< Sector > decodeSector(uint8_t sectorNum) const
Get a sector with a specific number.
std::span< uint8_t > getRawBuffer()
void writeBlock(int idx, std::span< const uint8_t > source)
void clear(unsigned size)
Clear track data.
void readBlock(int idx, std::span< uint8_t > destination) const
Like memcpy() but copy from/to circular buffer.
unsigned getLength() const
Get track length.
This class represents the result of a sha1 calculation (a 160-bit value).
This file implemented 3 utility functions:
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
std::array< uint8_t, 512 > raw
constexpr auto xrange(T e)