mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add minimal D88 image format reader.
This implements a subset of D88, only supporting the first floppy in an image. It only supports images with equal sector sizes, equal numbers of sectors per track, and no bad sectors.
This commit is contained in:
11
doc/using.md
11
doc/using.md
@@ -267,6 +267,17 @@ FluxEngine also supports a number of file system image formats. When using the
|
||||
Read from a [FDI image file](https://www.pc98.org/project/doc/hdi.html),
|
||||
commonly used by PC-98 emulators. **Read Only.**
|
||||
|
||||
- `<filename.d88>`
|
||||
|
||||
Read from a [D88 image file](https://www.pc98.org/project/doc/d88.html),
|
||||
commonly used by various Japanese PC emulators, including the NEC PC-88. **Read Only.**
|
||||
|
||||
FluxEngine is currently limited to reading only the first floppy image in a
|
||||
D88 file.
|
||||
|
||||
In addition, it only supports a limited subset of D88 features and will
|
||||
reject files not in that subset.
|
||||
|
||||
- `<filename.ldbs>`
|
||||
|
||||
Write to a [LDBS generic image
|
||||
|
||||
138
lib/imagereader/d88imagereader.cc
Normal file
138
lib/imagereader/d88imagereader.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "sector.h"
|
||||
#include "imagereader/imagereader.h"
|
||||
#include "image.h"
|
||||
#include "lib/config.pb.h"
|
||||
#include "imagereader/imagereaderimpl.h"
|
||||
#include "fmt/format.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
// reader based on this partial documentation of the D88 format:
|
||||
// https://www.pc98.org/project/doc/d88.html
|
||||
|
||||
class D88ImageReader : public ImageReader
|
||||
{
|
||||
public:
|
||||
D88ImageReader(const ImageReaderProto& config):
|
||||
ImageReader(config)
|
||||
{}
|
||||
|
||||
std::unique_ptr<Image> readImage()
|
||||
{
|
||||
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
|
||||
if (!inputFile.is_open())
|
||||
Error() << "cannot open input file";
|
||||
|
||||
Bytes header(0x24); // read first entry of track table as well
|
||||
inputFile.read((char*) header.begin(), header.size());
|
||||
|
||||
// the DIM header technically has a bit field for sectors present,
|
||||
// however it is currently ignored by this reader
|
||||
|
||||
std::string diskName = header.slice(0, 0x16);
|
||||
|
||||
if (diskName[0])
|
||||
std::cout << "D88: disk name: " << diskName << "\n";
|
||||
|
||||
ByteReader headerReader(header);
|
||||
|
||||
// media flag indicates media density, currently unused
|
||||
char mediaFlag = headerReader.seek(0x1b).read_8();
|
||||
|
||||
inputFile.seekg( 0, std::ios::end );
|
||||
int fileSize = inputFile.tellg();
|
||||
|
||||
int diskSize = headerReader.seek(0x1c).read_le32();
|
||||
|
||||
if (diskSize > fileSize)
|
||||
std::cout << "D88: found multiple disk images. Only using first\n";
|
||||
|
||||
int trackTableEnd = headerReader.seek(0x20).read_le32();
|
||||
int trackTableSize = trackTableEnd - 0x20;
|
||||
|
||||
Bytes trackTable(trackTableSize);
|
||||
inputFile.seekg(0x20);
|
||||
inputFile.read((char*) trackTable.begin(), trackTable.size());
|
||||
ByteReader trackTableReader(trackTable);
|
||||
|
||||
int diskSectorsPerTrack = -1;
|
||||
int diskSectorSize = -1;
|
||||
|
||||
std::unique_ptr<Image> image(new Image);
|
||||
for (int track = 0; track < trackTableSize / 4; track++)
|
||||
{
|
||||
int trackOffset = trackTableReader.seek(track * 4).read_le32();
|
||||
if (trackOffset == 0) continue;
|
||||
|
||||
int currentTrackOffset = trackOffset;
|
||||
int currentTrackCylinder = -1;
|
||||
int currentSectorsInTrack = 0xffff; // don't know # of sectors until we read the first one
|
||||
for (int sectorInTrack = 0; sectorInTrack < currentSectorsInTrack; sectorInTrack++){
|
||||
Bytes sectorHeader(0x10);
|
||||
inputFile.read((char*) sectorHeader.begin(), sectorHeader.size());
|
||||
ByteReader sectorHeaderReader(sectorHeader);
|
||||
char cylinder = sectorHeaderReader.seek(0).read_8();
|
||||
char head = sectorHeaderReader.seek(1).read_8();
|
||||
char sectorId = sectorHeaderReader.seek(2).read_8();
|
||||
int sectorSize = 128 << sectorHeaderReader.seek(3).read_8();
|
||||
int sectorsInTrack = sectorHeaderReader.seek(4).read_le16();
|
||||
int mfm = sectorHeaderReader.seek(6).read_8();
|
||||
int ddam = sectorHeaderReader.seek(7).read_8();
|
||||
int fddStatusCode = sectorHeaderReader.seek(8).read_8();
|
||||
// D88 provides much more sector information that is currently ignored
|
||||
if (ddam != 0)
|
||||
Error() << "D88: nonzero ddam currently unsupported";
|
||||
if (fddStatusCode != 0)
|
||||
Error() << "D88: nonzero fdd status codes are currently unsupported";
|
||||
if (currentSectorsInTrack == 0xffff) {
|
||||
currentSectorsInTrack = sectorsInTrack;
|
||||
} else if (currentSectorsInTrack != sectorsInTrack) {
|
||||
Error() << "D88: mismatched number of sectors in track";
|
||||
}
|
||||
if (diskSectorsPerTrack < 0) {
|
||||
diskSectorsPerTrack = sectorsInTrack;
|
||||
} else if (diskSectorsPerTrack != sectorsInTrack) {
|
||||
Error() << "D88: varying numbers of sectors per track is currently unsupported";
|
||||
}
|
||||
if (diskSectorSize < 0) {
|
||||
diskSectorSize = sectorSize;
|
||||
} else if (diskSectorSize != sectorSize) {
|
||||
Error() << "D88: variable sector sizes are currently unsupported";
|
||||
}
|
||||
if (mfm != 0)
|
||||
Error() << "D88: Non-MFM sectors are currenty unsupported";
|
||||
if (currentTrackCylinder < 0) {
|
||||
currentTrackCylinder = cylinder;
|
||||
} else if (currentTrackCylinder != cylinder) {
|
||||
Error() << "D88: all sectors in a track must belong to the same cylinder";
|
||||
}
|
||||
Bytes data(sectorSize);
|
||||
inputFile.read((char*) data.begin(), data.size());
|
||||
const auto& sector = image->put(cylinder, head, sectorId);
|
||||
sector->status = Sector::OK;
|
||||
sector->logicalTrack = cylinder;
|
||||
sector->physicalCylinder = cylinder;
|
||||
sector->logicalSide = sector->physicalHead = head;
|
||||
sector->logicalSector = sectorId;
|
||||
sector->data = data;
|
||||
}
|
||||
}
|
||||
|
||||
image->calculateSize();
|
||||
const Geometry& geometry = image->getGeometry();
|
||||
std::cout << fmt::format("D88: read {} tracks, {} sides\n",
|
||||
geometry.numTracks, geometry.numSides);
|
||||
return image;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::unique_ptr<ImageReader> ImageReader::createD88ImageReader(
|
||||
const ImageReaderProto& config)
|
||||
{
|
||||
return std::unique_ptr<ImageReader>(new D88ImageReader(config));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageReaderProto& config)
|
||||
case ImageReaderProto::kDim:
|
||||
return ImageReader::createDimImageReader(config);
|
||||
|
||||
case ImageReaderProto::kD88:
|
||||
return ImageReader::createD88ImageReader(config);
|
||||
|
||||
case ImageReaderProto::kFdi:
|
||||
return ImageReader::createFdiImageReader(config);
|
||||
|
||||
@@ -55,6 +58,7 @@ void ImageReader::updateConfigForFilename(ImageReaderProto* proto, const std::st
|
||||
{".jv3", [&]() { proto->mutable_jv3(); }},
|
||||
{".d64", [&]() { proto->mutable_d64(); }},
|
||||
{".d81", [&]() { proto->mutable_img(); }},
|
||||
{".d88", [&]() { proto->mutable_d88(); }},
|
||||
{".dim", [&]() { proto->mutable_dim(); }},
|
||||
{".diskcopy", [&]() { proto->mutable_diskcopy(); }},
|
||||
{".fdi", [&]() { proto->mutable_fdi(); }},
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
static std::unique_ptr<ImageReader> createTd0ImageReader(const ImageReaderProto& config);
|
||||
static std::unique_ptr<ImageReader> createDimImageReader(const ImageReaderProto& config);
|
||||
static std::unique_ptr<ImageReader> createFdiImageReader(const ImageReaderProto& config);
|
||||
static std::unique_ptr<ImageReader> createD88ImageReader(const ImageReaderProto& config);
|
||||
|
||||
public:
|
||||
virtual std::unique_ptr<Image> readImage() = 0;
|
||||
|
||||
@@ -40,6 +40,7 @@ message NsiInputProto {}
|
||||
message Td0InputProto {}
|
||||
message DimInputProto {}
|
||||
message FdiInputProto {}
|
||||
message D88InputProto {}
|
||||
|
||||
message ImageReaderProto {
|
||||
optional string filename = 1 [(help) = "filename of input sector image"];
|
||||
@@ -53,6 +54,7 @@ message ImageReaderProto {
|
||||
Td0InputProto td0 = 8;
|
||||
DimInputProto dim = 9;
|
||||
FdiInputProto fdi = 10;
|
||||
D88InputProto d88 = 11;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -374,6 +374,7 @@ buildlibrary libbackend.a \
|
||||
lib/imagereader/td0imagereader.cc \
|
||||
lib/imagereader/dimimagereader.cc \
|
||||
lib/imagereader/fdiimagereader.cc \
|
||||
lib/imagereader/d88imagereader.cc \
|
||||
lib/imagewriter/d64imagewriter.cc \
|
||||
lib/imagewriter/diskcopyimagewriter.cc \
|
||||
lib/imagewriter/imagewriter.cc \
|
||||
|
||||
Reference in New Issue
Block a user