diff --git a/doc/using.md b/doc/using.md index fe190c0b..da84a38c 100644 --- a/doc/using.md +++ b/doc/using.md @@ -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 diff --git a/lib/image.cc b/lib/image.cc index 113111a7..37fd33b0 100644 --- a/lib/image.cc +++ b/lib/image.cc @@ -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 #include #include -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 = 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) diff --git a/lib/image.h b/lib/image.h index 4adab91f..f1d6dd6f 100644 --- a/lib/image.h +++ b/lib/image.h @@ -4,8 +4,7 @@ class SectorSet; class ImageSpec; -extern void readSectorsFromFile( - SectorSet& sectors, +extern SectorSet readSectorsFromFile( const ImageSpec& filename); extern void writeSectorsToFile( diff --git a/lib/imagereader/imagereader.cc b/lib/imagereader/imagereader.cc new file mode 100644 index 00000000..4fe62777 --- /dev/null +++ b/lib/imagereader/imagereader.cc @@ -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::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(const ImageSpec& spec): + spec(spec) +{} + diff --git a/lib/imagereader/imagereader.h b/lib/imagereader/imagereader.h new file mode 100644 index 00000000..5b74544e --- /dev/null +++ b/lib/imagereader/imagereader.h @@ -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 create(const ImageSpec& spec); + +private: + static std::unique_ptr createImgImageReader(const ImageSpec& spec); + +public: + virtual SectorSet readImage() = 0; + +protected: + ImageSpec spec; +}; + +#endif + diff --git a/lib/imagereader/imgimagereader.cc b/lib/imagereader/imgimagereader.cc new file mode 100644 index 00000000..9a1311a8 --- /dev/null +++ b/lib/imagereader/imgimagereader.cc @@ -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 +#include +#include + +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 = 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::createImgImageReader( + const ImageSpec& spec) +{ + return std::unique_ptr(new ImgImageReader(spec)); +} + diff --git a/lib/imagewriter/imgimagewriter.cc b/lib/imagewriter/imgimagewriter.cc index c39034ae..e18cdd85 100644 --- a/lib/imagewriter/imgimagewriter.cc +++ b/lib/imagewriter/imgimagewriter.cc @@ -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) diff --git a/lib/writer.cc b/lib/writer.cc index d31d3a0d..269682a0 100644 --- a/lib/writer.cc +++ b/lib/writer.cc @@ -115,10 +115,8 @@ void fillBitmapTo(std::vector& 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 { diff --git a/mkninja.sh b/mkninja.sh index 1d66febd..dbc3f010 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -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 \