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));
 | |
| }
 |