mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
178 lines
5.1 KiB
C++
178 lines
5.1 KiB
C++
#include "lib/core/globals.h"
|
|
#include "lib/config/flags.h"
|
|
#include "lib/data/sector.h"
|
|
#include "lib/imagewriter/imagewriter.h"
|
|
#include "lib/external/ldbs.h"
|
|
#include "lib/data/image.h"
|
|
#include "lib/core/logger.h"
|
|
#include "lib/config/config.pb.h"
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
static const char LABEL[] = "FluxEngine image";
|
|
|
|
static void write_and_update_checksum(
|
|
ByteWriter& bw, uint32_t& checksum, const Bytes& data)
|
|
{
|
|
ByteReader br(data);
|
|
while (!br.eof())
|
|
{
|
|
uint32_t i = br.read_be16();
|
|
checksum += i;
|
|
checksum = (checksum >> 1) | (checksum << 31);
|
|
bw.write_be16(i);
|
|
}
|
|
}
|
|
|
|
class DiskCopyImageWriter : public ImageWriter
|
|
{
|
|
public:
|
|
DiskCopyImageWriter(const ImageWriterProto& config): ImageWriter(config) {}
|
|
|
|
void writeImage(const Image& image) override
|
|
{
|
|
const Geometry& geometry = image.getGeometry();
|
|
|
|
bool mfm = false;
|
|
|
|
switch (geometry.sectorSize)
|
|
{
|
|
case 524:
|
|
/* GCR disk */
|
|
break;
|
|
|
|
case 512:
|
|
/* MFM disk */
|
|
mfm = true;
|
|
break;
|
|
|
|
default:
|
|
error(
|
|
"this image is not compatible with the DiskCopy 4.2 "
|
|
"format");
|
|
}
|
|
|
|
log("DC42: writing DiskCopy 4.2 image");
|
|
log("DC42: {} tracks, {} sides, {} sectors, {} bytes per sector; {}",
|
|
geometry.numTracks,
|
|
geometry.numSides,
|
|
geometry.numSectors,
|
|
geometry.sectorSize,
|
|
mfm ? "MFM" : "GCR");
|
|
|
|
auto sectors_per_track = [&](int track) -> int
|
|
{
|
|
if (mfm)
|
|
return geometry.numSectors;
|
|
|
|
if (track < 16)
|
|
return 12;
|
|
if (track < 32)
|
|
return 11;
|
|
if (track < 48)
|
|
return 10;
|
|
if (track < 64)
|
|
return 9;
|
|
return 8;
|
|
};
|
|
|
|
Bytes data;
|
|
ByteWriter bw(data);
|
|
|
|
/* Write the actual sectr data. */
|
|
|
|
uint32_t dataChecksum = 0;
|
|
uint32_t tagChecksum = 0;
|
|
uint32_t offset = 0x54;
|
|
uint32_t sectorDataStart = offset;
|
|
for (int track = 0; track < geometry.numTracks; track++)
|
|
{
|
|
for (int side = 0; side < geometry.numSides; side++)
|
|
{
|
|
int sectorCount = sectors_per_track(track);
|
|
for (int sectorId = 0; sectorId < sectorCount; sectorId++)
|
|
{
|
|
const auto& sector = image.get(track, side, sectorId);
|
|
if (sector)
|
|
{
|
|
bw.seek(offset);
|
|
write_and_update_checksum(
|
|
bw, dataChecksum, sector->data.slice(0, 512));
|
|
}
|
|
offset += 512;
|
|
}
|
|
}
|
|
}
|
|
uint32_t sectorDataEnd = offset;
|
|
if (!mfm)
|
|
{
|
|
for (int track = 0; track < geometry.numTracks; track++)
|
|
{
|
|
for (int side = 0; side < geometry.numSides; side++)
|
|
{
|
|
int sectorCount = sectors_per_track(track);
|
|
for (int sectorId = 0; sectorId < sectorCount; sectorId++)
|
|
{
|
|
const auto& sector = image.get(track, side, sectorId);
|
|
if (sector)
|
|
{
|
|
bw.seek(offset);
|
|
write_and_update_checksum(
|
|
bw, tagChecksum, sector->data.slice(512, 12));
|
|
}
|
|
offset += 12;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
uint32_t tagDataEnd = offset;
|
|
|
|
/* Write the header. */
|
|
|
|
uint8_t encoding;
|
|
uint8_t format;
|
|
if (mfm)
|
|
{
|
|
format = 0x22;
|
|
if (geometry.numSectors == 18)
|
|
encoding = 3;
|
|
else
|
|
encoding = 2;
|
|
}
|
|
else
|
|
{
|
|
if (geometry.numSides == 2)
|
|
{
|
|
encoding = 1;
|
|
format = 0x22;
|
|
}
|
|
else
|
|
{
|
|
encoding = 0;
|
|
format = 0x02;
|
|
}
|
|
}
|
|
|
|
bw.seek(0);
|
|
bw.write_8(sizeof(LABEL));
|
|
bw.append(LABEL);
|
|
bw.seek(0x40);
|
|
bw.write_be32(sectorDataEnd - sectorDataStart); /* data size */
|
|
bw.write_be32(tagDataEnd - sectorDataEnd); /* tag size */
|
|
bw.write_be32(dataChecksum); /* data checksum */
|
|
bw.write_be32(tagChecksum); /* tag checksum */
|
|
bw.write_8(encoding); /* encoding */
|
|
bw.write_8(format); /* format byte */
|
|
bw.write_be16(0x0100); /* magic number */
|
|
|
|
data.writeToFile(_config.filename());
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<ImageWriter> ImageWriter::createDiskCopyImageWriter(
|
|
const ImageWriterProto& config)
|
|
{
|
|
return std::unique_ptr<ImageWriter>(new DiskCopyImageWriter(config));
|
|
}
|