#include "globals.h" #include "flags.h" #include "sector.h" #include "imagewriter/imagewriter.h" #include "image.h" #include "lib/config.pb.h" #include "imginputoutpututils.h" #include "fmt/format.h" #include "logger.h" #include #include #include class D88ImageWriter : public ImageWriter { public: D88ImageWriter(const ImageWriterProto& config): ImageWriter(config) {} void writeImage(const Image& image) { const Geometry geometry = image.getGeometry(); int tracks = geometry.numTracks; int sides = geometry.numSides; std::ofstream outputFile(_config.filename(), std::ios::out | std::ios::binary); if (!outputFile.is_open()) Error() << "cannot open output file"; Bytes header; ByteWriter headerWriter(header); for(int i = 0; i < 26; i++) { headerWriter.write_8(0x0); // image name + reserved bytes } headerWriter.write_8(0x00); // not write protected if (geometry.numTracks > 42) { headerWriter.write_8(0x20); // 2HD } else { headerWriter.write_8(0x00); // 2D } headerWriter.write_le32(0); // disk size (will be overridden at the end of writing) for (int i = 0; i < 164; i++) { headerWriter.write_le32(0); // track pointer (will be overridden in track loop) } header.writeTo(outputFile); uint32_t trackOffset = 688; for (int track = 0; track < geometry.numTracks * geometry.numSides; track++) { headerWriter.seek(0x20 + 4 * track); headerWriter.write_le32(trackOffset); int side = track & 1; std::vector> sectors; for (int sectorId = 0; sectorId < geometry.numSectors; sectorId++) { const auto& sector = image.get(track >> 1, side, sectorId); if (sector) { sectors.push_back(sector); } } std::sort(begin(sectors), end(sectors), [](std::shared_ptr a, std::shared_ptr b) { return a->position < b->position; }); for (auto& sector : sectors) { Bytes sectorBytes; ByteWriter sectorWriter(sectorBytes); sectorWriter.write_8(sector->logicalTrack); sectorWriter.write_8(sector->logicalSide); sectorWriter.write_8(sector->logicalSector); sectorWriter.write_8(24 - std::countl_zero(uint32_t(sector->data.size()))); sectorWriter.write_le16(sectors.size()); sectorWriter.write_8(0x00); // always write mfm sectorWriter.write_8(0x00); // always write not deleted data if (sector->status == Sector::Status::BAD_CHECKSUM) { sectorWriter.write_8(0xB0); } else { sectorWriter.write_8(0x00); } sectorWriter.write_8(0x00); // reserved sectorWriter.write_8(0x00); sectorWriter.write_8(0x00); sectorWriter.write_8(0x00); sectorWriter.write_8(0x00); sectorWriter.write_le16(sector->data.size()); sectorBytes.writeTo(outputFile); sector->data.writeTo(outputFile); trackOffset += sectorBytes.size(); trackOffset += sector->data.size(); } } headerWriter.seek(0x1c); headerWriter.write_le32(outputFile.tellp()); outputFile.seekp(0); header.writeTo(outputFile); Logger() << fmt::format("D88: wrote {} tracks, {} sides, {} kB total", tracks, sides, outputFile.tellp() / 1024); } }; std::unique_ptr ImageWriter::createD88ImageWriter( const ImageWriterProto& config) { return std::unique_ptr(new D88ImageWriter(config)); }