mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Merge pull request #357 from tdaede/d88
Add minimal D88 image format reader.
This commit is contained in:
		
							
								
								
									
										11
									
								
								doc/using.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								doc/using.md
									
									
									
									
									
								
							| @@ -267,6 +267,17 @@ FluxEngine also supports a number of file system image formats. When using the | ||||
|   Read from a [FDI image file](https://www.pc98.org/project/doc/hdi.html), | ||||
|   commonly used by PC-98 emulators. **Read Only.** | ||||
|    | ||||
|   - `<filename.d88>` | ||||
|  | ||||
|   Read from a [D88 image file](https://www.pc98.org/project/doc/d88.html), | ||||
|   commonly used by various Japanese PC emulators, including the NEC PC-88. **Read Only.** | ||||
|    | ||||
|   FluxEngine is currently limited to reading only the first floppy image in a | ||||
|   D88 file. | ||||
|    | ||||
|   In addition, it only supports a limited subset of D88 features and will | ||||
|   reject files not in that subset. | ||||
|    | ||||
|   - `<filename.ldbs>` | ||||
|  | ||||
| 	Write to a [LDBS generic image | ||||
|   | ||||
							
								
								
									
										138
									
								
								lib/imagereader/d88imagereader.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								lib/imagereader/d88imagereader.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "sector.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "image.h" | ||||
| #include "lib/config.pb.h" | ||||
| #include "imagereader/imagereaderimpl.h" | ||||
| #include "fmt/format.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| // reader based on this partial documentation of the D88 format: | ||||
| // https://www.pc98.org/project/doc/d88.html | ||||
|  | ||||
| class D88ImageReader : public ImageReader | ||||
| { | ||||
| public: | ||||
| 	D88ImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	std::unique_ptr<Image> readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
|         Bytes header(0x24); // read first entry of track table as well | ||||
|         inputFile.read((char*) header.begin(), header.size()); | ||||
|  | ||||
|         // the DIM header technically has a bit field for sectors present, | ||||
|         // however it is currently ignored by this reader | ||||
|  | ||||
|         std::string diskName = header.slice(0, 0x16); | ||||
|  | ||||
|         if (diskName[0]) | ||||
|             std::cout << "D88: disk name: " << diskName << "\n"; | ||||
|  | ||||
|         ByteReader headerReader(header); | ||||
|  | ||||
|         // media flag indicates media density, currently unused | ||||
|         char mediaFlag = headerReader.seek(0x1b).read_8(); | ||||
|  | ||||
|         inputFile.seekg( 0, std::ios::end ); | ||||
|         int fileSize = inputFile.tellg(); | ||||
|  | ||||
|         int diskSize = headerReader.seek(0x1c).read_le32(); | ||||
|  | ||||
|         if (diskSize > fileSize) | ||||
|             std::cout << "D88: found multiple disk images. Only using first\n"; | ||||
|  | ||||
|         int trackTableEnd = headerReader.seek(0x20).read_le32(); | ||||
|         int trackTableSize = trackTableEnd - 0x20; | ||||
|  | ||||
|         Bytes trackTable(trackTableSize); | ||||
|         inputFile.seekg(0x20); | ||||
|         inputFile.read((char*) trackTable.begin(), trackTable.size()); | ||||
|         ByteReader trackTableReader(trackTable); | ||||
|  | ||||
|         int diskSectorsPerTrack = -1; | ||||
|         int diskSectorSize = -1; | ||||
|  | ||||
|         std::unique_ptr<Image> image(new Image); | ||||
|         for (int track = 0; track < trackTableSize / 4; track++) | ||||
|         { | ||||
|             int trackOffset = trackTableReader.seek(track * 4).read_le32(); | ||||
|             if (trackOffset == 0) continue; | ||||
|  | ||||
|             int currentTrackOffset = trackOffset; | ||||
|             int currentTrackCylinder = -1; | ||||
|             int currentSectorsInTrack = 0xffff; // don't know # of sectors until we read the first one | ||||
|             for (int sectorInTrack = 0; sectorInTrack < currentSectorsInTrack; sectorInTrack++){ | ||||
|                 Bytes sectorHeader(0x10); | ||||
|                 inputFile.read((char*) sectorHeader.begin(), sectorHeader.size()); | ||||
|                 ByteReader sectorHeaderReader(sectorHeader); | ||||
|                 char cylinder = sectorHeaderReader.seek(0).read_8(); | ||||
|                 char head = sectorHeaderReader.seek(1).read_8(); | ||||
|                 char sectorId = sectorHeaderReader.seek(2).read_8(); | ||||
|                 int sectorSize = 128 << sectorHeaderReader.seek(3).read_8(); | ||||
|                 int sectorsInTrack = sectorHeaderReader.seek(4).read_le16(); | ||||
|                 int mfm = sectorHeaderReader.seek(6).read_8(); | ||||
|                 int ddam = sectorHeaderReader.seek(7).read_8(); | ||||
|                 int fddStatusCode = sectorHeaderReader.seek(8).read_8(); | ||||
|                 // D88 provides much more sector information that is currently ignored | ||||
|                 if (ddam != 0) | ||||
|                     Error() << "D88: nonzero ddam currently unsupported"; | ||||
|                 if (fddStatusCode != 0) | ||||
|                     Error() << "D88: nonzero fdd status codes are currently unsupported"; | ||||
|                 if (currentSectorsInTrack == 0xffff) { | ||||
|                     currentSectorsInTrack = sectorsInTrack; | ||||
|                 } else if (currentSectorsInTrack != sectorsInTrack) { | ||||
|                     Error() << "D88: mismatched number of sectors in track"; | ||||
|                 } | ||||
|                 if (diskSectorsPerTrack < 0) { | ||||
|                     diskSectorsPerTrack = sectorsInTrack; | ||||
|                 } else if (diskSectorsPerTrack != sectorsInTrack) { | ||||
|                     Error() << "D88: varying numbers of sectors per track is currently unsupported"; | ||||
|                 } | ||||
|                 if (diskSectorSize < 0) { | ||||
|                     diskSectorSize = sectorSize; | ||||
|                 } else if (diskSectorSize != sectorSize) { | ||||
|                     Error() << "D88: variable sector sizes are currently unsupported"; | ||||
|                 } | ||||
|                 if (mfm != 0) | ||||
|                     Error() << "D88: Non-MFM sectors are currenty unsupported"; | ||||
|                 if (currentTrackCylinder < 0) { | ||||
|                     currentTrackCylinder = cylinder; | ||||
|                 } else if (currentTrackCylinder != cylinder) { | ||||
|                     Error() << "D88: all sectors in a track must belong to the same cylinder"; | ||||
|                 } | ||||
|                 Bytes data(sectorSize); | ||||
|                 inputFile.read((char*) data.begin(), data.size()); | ||||
|                 const auto& sector = image->put(cylinder, head, sectorId); | ||||
|                 sector->status = Sector::OK; | ||||
|                 sector->logicalTrack = cylinder; | ||||
|                 sector->physicalCylinder = cylinder; | ||||
|                 sector->logicalSide = sector->physicalHead = head; | ||||
|                 sector->logicalSector = sectorId; | ||||
|                 sector->data = data; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         image->calculateSize(); | ||||
|         const Geometry& geometry = image->getGeometry(); | ||||
|         std::cout << fmt::format("D88: read {} tracks, {} sides\n", | ||||
|                         geometry.numTracks, geometry.numSides); | ||||
|         return image; | ||||
|     } | ||||
|  | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createD88ImageReader( | ||||
| 	const ImageReaderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<ImageReader>(new D88ImageReader(config)); | ||||
| } | ||||
|  | ||||
| @@ -17,6 +17,9 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageReaderProto& config) | ||||
| 		case ImageReaderProto::kDim: | ||||
| 			return ImageReader::createDimImageReader(config); | ||||
|  | ||||
| 		case ImageReaderProto::kD88: | ||||
| 			return ImageReader::createD88ImageReader(config); | ||||
|  | ||||
| 		case ImageReaderProto::kFdi: | ||||
| 			return ImageReader::createFdiImageReader(config); | ||||
|  | ||||
| @@ -55,6 +58,7 @@ void ImageReader::updateConfigForFilename(ImageReaderProto* proto, const std::st | ||||
| 		{".jv3",      [&]() { proto->mutable_jv3(); }}, | ||||
| 		{".d64",      [&]() { proto->mutable_d64(); }}, | ||||
| 		{".d81",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".d88",      [&]() { proto->mutable_d88(); }}, | ||||
| 		{".dim",      [&]() { proto->mutable_dim(); }}, | ||||
| 		{".diskcopy", [&]() { proto->mutable_diskcopy(); }}, | ||||
| 		{".fdi",      [&]() { proto->mutable_fdi(); }}, | ||||
|   | ||||
| @@ -26,6 +26,7 @@ public: | ||||
|     static std::unique_ptr<ImageReader> createTd0ImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createDimImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createFdiImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createD88ImageReader(const ImageReaderProto& config); | ||||
|  | ||||
| public: | ||||
| 	virtual std::unique_ptr<Image> readImage() = 0; | ||||
|   | ||||
| @@ -40,6 +40,7 @@ message NsiInputProto {} | ||||
| message Td0InputProto {} | ||||
| message DimInputProto {} | ||||
| message FdiInputProto {} | ||||
| message D88InputProto {} | ||||
|  | ||||
| message ImageReaderProto { | ||||
| 	optional string filename = 1 [(help) = "filename of input sector image"]; | ||||
| @@ -53,6 +54,7 @@ message ImageReaderProto { | ||||
| 		Td0InputProto td0 = 8; | ||||
| 		DimInputProto dim = 9; | ||||
| 		FdiInputProto fdi = 10; | ||||
| 		D88InputProto d88 = 11; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -374,6 +374,7 @@ buildlibrary libbackend.a \ | ||||
|     lib/imagereader/td0imagereader.cc \ | ||||
|     lib/imagereader/dimimagereader.cc \ | ||||
|     lib/imagereader/fdiimagereader.cc \ | ||||
|     lib/imagereader/d88imagereader.cc \ | ||||
|     lib/imagewriter/d64imagewriter.cc \ | ||||
|     lib/imagewriter/diskcopyimagewriter.cc \ | ||||
|     lib/imagewriter/imagewriter.cc \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user