Add pluggable image readers, plus some documentation.

This commit is contained in:
David Given
2019-08-09 20:56:06 +02:00
parent 87e29fc386
commit 112377f885
9 changed files with 149 additions and 41 deletions

View File

@@ -112,6 +112,23 @@ sensible for the command you're using.
**Important note:** FluxEngine _always_ uses zero-based units (even if the
*disk format says otherwise).
### Input and output specifiers
These use a very similar syntax to the source and destination specifiers
(because they're based on the same microformat library!) but are used for
input and output _images_: i.e. nicely lined up arrays of sectors which you
can actually do something with.
Use `--input` (`-i`) or `--output` (`-o`) as appropriate to tell FluxEngine
where you want to read from or write to. The actual format is autodetected
based on the extension:
- `.img` or `.adf`: raw sector images in CHS order. Append
`:c=80:h=2:s=9:b=512` to set the geometry; that specifies 80 cylinders, 2
heads, 9 sectors, 512 bytes per sector. For output files (`--output`) the
geometry will be autodetected if left unspecified. For input files you
normally have to specify it.
### High density disks
High density disks use a different magnetic medium to low and double density

View File

@@ -4,48 +4,16 @@
#include "dataspec.h"
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "imagewriter/imagewriter.h"
#include "fmt/format.h"
#include <algorithm>
#include <iostream>
#include <fstream>
void readSectorsFromFile(SectorSet& sectors, const ImageSpec& spec)
SectorSet readSectorsFromFile(const ImageSpec& spec)
{
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
size_t headSize = spec.sectors * spec.bytes;
size_t trackSize = headSize * spec.heads;
std::cout << fmt::format("{} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total",
spec.cylinders, spec.heads,
spec.sectors, spec.bytes,
spec.cylinders * trackSize / 1024)
<< std::endl;
for (int track = 0; track < spec.cylinders; track++)
{
for (int head = 0; head < spec.heads; head++)
{
for (int sectorId = 0; sectorId < spec.sectors; sectorId++)
{
inputFile.seekg(track*trackSize + head*headSize + sectorId*spec.bytes, std::ios::beg);
Bytes data(spec.bytes);
inputFile.read((char*) data.begin(), spec.bytes);
std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId);
sector.reset(new Sector);
sector->status = Sector::OK;
sector->logicalTrack = sector->physicalTrack = track;
sector->logicalSide = sector->physicalSide = head;
sector->logicalSector = sectorId;
sector->data = data;
}
}
}
return ImageReader::create(spec)->readImage();
}
void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec)

View File

@@ -4,8 +4,7 @@
class SectorSet;
class ImageSpec;
extern void readSectorsFromFile(
SectorSet& sectors,
extern SectorSet readSectorsFromFile(
const ImageSpec& filename);
extern void writeSectorsToFile(

View File

@@ -0,0 +1,31 @@
#include "globals.h"
#include "image.h"
#include "flags.h"
#include "dataspec.h"
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "fmt/format.h"
static bool ends_with(const std::string& value, const std::string& ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
std::unique_ptr<ImageReader> ImageReader::create(const ImageSpec& spec)
{
const auto& filename = spec.filename;
if (ends_with(filename, ".img") || ends_with(filename, ".adf"))
return createImgImageReader(spec);
Error() << "unrecognised image filename extension";
return std::unique_ptr<ImageReader>();
}
ImageReader::ImageReader(const ImageSpec& spec):
spec(spec)
{}

View File

@@ -0,0 +1,27 @@
#ifndef IMAGEREADER_H
#define IMAGEREADER_H
class SectorSet;
class ImageSpec;
class ImageReader
{
public:
ImageReader(const ImageSpec& spec);
virtual ~ImageReader() {};
public:
static std::unique_ptr<ImageReader> create(const ImageSpec& spec);
private:
static std::unique_ptr<ImageReader> createImgImageReader(const ImageSpec& spec);
public:
virtual SectorSet readImage() = 0;
protected:
ImageSpec spec;
};
#endif

View File

@@ -0,0 +1,66 @@
#include "globals.h"
#include "image.h"
#include "flags.h"
#include "dataspec.h"
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "fmt/format.h"
#include <algorithm>
#include <iostream>
#include <fstream>
class ImgImageReader : public ImageReader
{
public:
ImgImageReader(const ImageSpec& spec):
ImageReader(spec)
{}
SectorSet readImage()
{
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
size_t headSize = spec.sectors * spec.bytes;
size_t trackSize = headSize * spec.heads;
std::cout << fmt::format("reading {} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total",
spec.cylinders, spec.heads,
spec.sectors, spec.bytes,
spec.cylinders * trackSize / 1024)
<< std::endl;
SectorSet sectors;
for (int track = 0; track < spec.cylinders; track++)
{
for (int head = 0; head < spec.heads; head++)
{
for (int sectorId = 0; sectorId < spec.sectors; sectorId++)
{
inputFile.seekg(track*trackSize + head*headSize + sectorId*spec.bytes, std::ios::beg);
Bytes data(spec.bytes);
inputFile.read((char*) data.begin(), spec.bytes);
std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId);
sector.reset(new Sector);
sector->status = Sector::OK;
sector->logicalTrack = sector->physicalTrack = track;
sector->logicalSide = sector->physicalSide = head;
sector->logicalSector = sectorId;
sector->data = data;
}
}
}
return sectors;
}
};
std::unique_ptr<ImageReader> ImageReader::createImgImageReader(
const ImageSpec& spec)
{
return std::unique_ptr<ImageReader>(new ImgImageReader(spec));
}

View File

@@ -27,7 +27,7 @@ public:
size_t headSize = numSectors * numBytes;
size_t trackSize = headSize * numHeads;
std::cout << fmt::format("{} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total",
std::cout << fmt::format("writing {} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total",
numCylinders, numHeads,
numSectors, numBytes,
numCylinders * trackSize / 1024)

View File

@@ -115,10 +115,8 @@ void fillBitmapTo(std::vector<bool>& bitmap,
void writeDiskCommand(AbstractEncoder& encoder)
{
SectorSet allSectors;
const ImageSpec spec(input);
readSectorsFromFile(allSectors, spec);
SectorSet allSectors = readSectorsFromFile(spec);
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{

View File

@@ -168,6 +168,8 @@ buildlibrary libbackend.a \
lib/fluxsource/kryoflux.cc \
lib/fluxsource/sqlitefluxsource.cc \
lib/fluxsource/streamfluxsource.cc \
lib/imagereader/imagereader.cc \
lib/imagereader/imgimagereader.cc \
lib/imagewriter/imagewriter.cc \
lib/imagewriter/imgimagewriter.cc \
lib/globals.cc \