mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-12 15:31:09 +00:00
Merge pull request #177 from TomHarte/DSKFileFormat
Introduces parsing of the file format support for the simplest of CPC disks
This commit is contained in:
commit
0f4343cd84
@ -92,6 +92,7 @@
|
|||||||
4B8378DF1F33675F005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378DD1F33675F005CA9E4 /* CharacterMapper.cpp */; };
|
4B8378DF1F33675F005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378DD1F33675F005CA9E4 /* CharacterMapper.cpp */; };
|
||||||
4B8378E21F336920005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E01F336920005CA9E4 /* CharacterMapper.cpp */; };
|
4B8378E21F336920005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E01F336920005CA9E4 /* CharacterMapper.cpp */; };
|
||||||
4B8378E51F3378C4005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */; };
|
4B8378E51F3378C4005CA9E4 /* CharacterMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */; };
|
||||||
|
4B838F1F1F35FDCD0016B5E6 /* CPCDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */; };
|
||||||
4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; };
|
4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; };
|
||||||
4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; };
|
4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; };
|
||||||
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */; };
|
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */; };
|
||||||
@ -618,6 +619,8 @@
|
|||||||
4B8378E11F336920005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CharacterMapper.hpp; path = Oric/CharacterMapper.hpp; sourceTree = "<group>"; };
|
4B8378E11F336920005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CharacterMapper.hpp; path = Oric/CharacterMapper.hpp; sourceTree = "<group>"; };
|
||||||
4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CharacterMapper.cpp; sourceTree = "<group>"; };
|
4B8378E31F3378C4005CA9E4 /* CharacterMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CharacterMapper.cpp; sourceTree = "<group>"; };
|
||||||
4B8378E41F3378C4005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CharacterMapper.hpp; sourceTree = "<group>"; };
|
4B8378E41F3378C4005CA9E4 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CharacterMapper.hpp; sourceTree = "<group>"; };
|
||||||
|
4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPCDSK.cpp; sourceTree = "<group>"; };
|
||||||
|
4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPCDSK.hpp; sourceTree = "<group>"; };
|
||||||
4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = "<group>"; };
|
4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = "<group>"; };
|
||||||
4B8805EF1DCFC99C003085B1 /* Acorn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Acorn.hpp; path = Parsers/Acorn.hpp; sourceTree = "<group>"; };
|
4B8805EF1DCFC99C003085B1 /* Acorn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Acorn.hpp; path = Parsers/Acorn.hpp; sourceTree = "<group>"; };
|
||||||
4B8805F21DCFD22A003085B1 /* Commodore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Commodore.cpp; path = Parsers/Commodore.cpp; sourceTree = "<group>"; };
|
4B8805F21DCFD22A003085B1 /* Commodore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Commodore.cpp; path = Parsers/Commodore.cpp; sourceTree = "<group>"; };
|
||||||
@ -1551,6 +1554,8 @@
|
|||||||
4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */,
|
4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */,
|
||||||
4BF829611D8F536B001BAE39 /* SSD.cpp */,
|
4BF829611D8F536B001BAE39 /* SSD.cpp */,
|
||||||
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
||||||
|
4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */,
|
||||||
|
4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */,
|
||||||
);
|
);
|
||||||
path = Formats;
|
path = Formats;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2751,6 +2756,7 @@
|
|||||||
4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */,
|
4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */,
|
||||||
4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */,
|
4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */,
|
||||||
4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */,
|
4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */,
|
||||||
|
4B838F1F1F35FDCD0016B5E6 /* CPCDSK.cpp in Sources */,
|
||||||
4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */,
|
4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */,
|
||||||
4B4C83701D4F623200CD541F /* D64.cpp in Sources */,
|
4B4C83701D4F623200CD541F /* D64.cpp in Sources */,
|
||||||
4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */,
|
4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */,
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
// Disks
|
// Disks
|
||||||
#include "../Storage/Disk/Formats/AcornADF.hpp"
|
#include "../Storage/Disk/Formats/AcornADF.hpp"
|
||||||
|
#include "../Storage/Disk/Formats/CPCDSK.hpp"
|
||||||
#include "../Storage/Disk/Formats/D64.hpp"
|
#include "../Storage/Disk/Formats/D64.hpp"
|
||||||
#include "../Storage/Disk/Formats/G64.hpp"
|
#include "../Storage/Disk/Formats/G64.hpp"
|
||||||
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
||||||
@ -99,7 +100,8 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name) {
|
|||||||
Format("csw", tapes, Tape::CSW, TargetPlatform::AllTape) // CSW
|
Format("csw", tapes, Tape::CSW, TargetPlatform::AllTape) // CSW
|
||||||
Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64
|
Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64
|
||||||
Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD
|
Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD
|
||||||
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK
|
Format("dsk", disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
||||||
|
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
||||||
Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64
|
Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64
|
||||||
Format("o", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
Format("o", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
||||||
Format("p", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
Format("p", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||||
|
126
Storage/Disk/Formats/CPCDSK.cpp
Normal file
126
Storage/Disk/Formats/CPCDSK.cpp
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// CPCDSK.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 05/08/2017.
|
||||||
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "CPCDSK.hpp"
|
||||||
|
|
||||||
|
#include "../Encodings/MFM.hpp"
|
||||||
|
|
||||||
|
using namespace Storage::Disk;
|
||||||
|
|
||||||
|
CPCDSK::CPCDSK(const char *file_name) :
|
||||||
|
Storage::FileHolder(file_name), is_extended_(false) {
|
||||||
|
if(!check_signature("MV - CPC", 8)) {
|
||||||
|
is_extended_ = true;
|
||||||
|
if(!check_signature("EXTENDED", 8))
|
||||||
|
throw ErrorNotCPCDSK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't really care about about the creator; skip.
|
||||||
|
fseek(file_, 0x30, SEEK_SET);
|
||||||
|
head_position_count_ = (unsigned int)fgetc(file_);
|
||||||
|
head_count_ = (unsigned int)fgetc(file_);
|
||||||
|
|
||||||
|
if(is_extended_) {
|
||||||
|
for(unsigned int c = 0; c < head_position_count_ * head_count_; c++) {
|
||||||
|
track_sizes_.push_back((size_t)(fgetc(file_) << 8));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_of_a_track_ = fgetc16le();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CPCDSK::get_head_position_count() {
|
||||||
|
return head_position_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CPCDSK::get_head_count() {
|
||||||
|
return head_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPCDSK::get_is_read_only() {
|
||||||
|
// TODO: allow writing.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Track> CPCDSK::get_uncached_track_at_position(unsigned int head, unsigned int position) {
|
||||||
|
// Given that thesea are interleaved images, determine which track, chronologically, is being requested.
|
||||||
|
unsigned int chronological_track = (position * head_count_) + head;
|
||||||
|
|
||||||
|
// All DSK images reserve 0x100 bytes for their headers.
|
||||||
|
long file_offset = 0x100;
|
||||||
|
if(is_extended_) {
|
||||||
|
// Tracks are a variable size in the original DSK file format; sum the lengths
|
||||||
|
// of all tracks prior to the interesting one to get a file offset.
|
||||||
|
unsigned int t = 0;
|
||||||
|
while(t < chronological_track && t < track_sizes_.size()) {
|
||||||
|
file_offset += track_sizes_[t];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Tracks are a fixed size in the original DSK file format.
|
||||||
|
file_offset += size_of_a_track_ * chronological_track;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the track, and skip the unused part of track information.
|
||||||
|
fseek(file_, file_offset + 16, SEEK_SET);
|
||||||
|
|
||||||
|
// Grab the track information.
|
||||||
|
fseek(file_, 5, SEEK_CUR); // skip track number, side number, sector size — each is given per sector
|
||||||
|
int number_of_sectors = fgetc(file_);
|
||||||
|
__unused uint8_t gap3_length = (uint8_t)fgetc(file_);
|
||||||
|
__unused uint8_t filler_byte = (uint8_t)fgetc(file_);
|
||||||
|
|
||||||
|
// Grab the sector information
|
||||||
|
struct SectorInfo {
|
||||||
|
uint8_t track;
|
||||||
|
uint8_t side;
|
||||||
|
uint8_t sector;
|
||||||
|
size_t length;
|
||||||
|
uint8_t status1;
|
||||||
|
uint8_t status2;
|
||||||
|
};
|
||||||
|
std::vector<SectorInfo> sector_infos;
|
||||||
|
while(number_of_sectors--) {
|
||||||
|
SectorInfo new_sector;
|
||||||
|
|
||||||
|
new_sector.track = (uint8_t)fgetc(file_);
|
||||||
|
new_sector.side = (uint8_t)fgetc(file_);
|
||||||
|
new_sector.sector = (uint8_t)fgetc(file_);
|
||||||
|
new_sector.length = (size_t)(128 << fgetc(file_));
|
||||||
|
if(new_sector.length == 0x2000) new_sector.length = 0x1800;
|
||||||
|
new_sector.status1 = (uint8_t)fgetc(file_);
|
||||||
|
new_sector.status2 = (uint8_t)fgetc(file_);
|
||||||
|
fseek(file_, 2, SEEK_CUR);
|
||||||
|
|
||||||
|
sector_infos.push_back(new_sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the sectors.
|
||||||
|
fseek(file_, file_offset + 0x100, SEEK_SET);
|
||||||
|
if(is_extended_) {
|
||||||
|
// TODO: everything about extended disk images
|
||||||
|
} else {
|
||||||
|
std::vector<Storage::Encodings::MFM::Sector> sectors;
|
||||||
|
for(auto §or_info : sector_infos) {
|
||||||
|
Storage::Encodings::MFM::Sector new_sector;
|
||||||
|
new_sector.track = sector_info.track;
|
||||||
|
new_sector.side = sector_info.side;
|
||||||
|
new_sector.sector = sector_info.sector;
|
||||||
|
new_sector.data.resize(sector_info.length);
|
||||||
|
fread(new_sector.data.data(), sizeof(uint8_t), sector_info.length, file_);
|
||||||
|
|
||||||
|
// TODO: obey the status bytes, somehow (?)
|
||||||
|
|
||||||
|
sectors.push_back(std::move(new_sector));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: supply gay 3 length and filler byte
|
||||||
|
if(sectors.size()) return Storage::Encodings::MFM::GetMFMTrackWithSectors(sectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
60
Storage/Disk/Formats/CPCDSK.hpp
Normal file
60
Storage/Disk/Formats/CPCDSK.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// CPCDSK.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 05/08/2017.
|
||||||
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CPCDSK_hpp
|
||||||
|
#define CPCDSK_hpp
|
||||||
|
|
||||||
|
#include "../Disk.hpp"
|
||||||
|
#include "../../FileHolder.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Disk {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Provies a @c Disk containing an Amstrad CPC-stype disk image — some arrangement of sectors with status bits.
|
||||||
|
*/
|
||||||
|
class CPCDSK: public Disk, public Storage::FileHolder {
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Construct an @c AcornADF containing content from the file with name @c file_name.
|
||||||
|
|
||||||
|
@throws ErrorCantOpen if this file can't be opened.
|
||||||
|
@throws ErrorNotAcornADF if the file doesn't appear to contain an Acorn .ADF format image.
|
||||||
|
*/
|
||||||
|
CPCDSK(const char *file_name);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ErrorNotCPCDSK,
|
||||||
|
};
|
||||||
|
|
||||||
|
// implemented to satisfy @c Disk
|
||||||
|
unsigned int get_head_position_count();
|
||||||
|
unsigned int get_head_count();
|
||||||
|
bool get_is_read_only();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Track> get_uncached_track_at_position(unsigned int head, unsigned int position);
|
||||||
|
|
||||||
|
unsigned int head_count_;
|
||||||
|
unsigned int head_position_count_;
|
||||||
|
bool is_extended_;
|
||||||
|
|
||||||
|
// Used only for non-extended disks.
|
||||||
|
long size_of_a_track_;
|
||||||
|
|
||||||
|
// Used only for extended disks.
|
||||||
|
std::vector<size_t> track_sizes_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CPCDSK_hpp */
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "SSD.hpp"
|
#include "SSD.hpp"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "../Encodings/MFM.hpp"
|
#include "../Encodings/MFM.hpp"
|
||||||
|
|
||||||
using namespace Storage::Disk;
|
using namespace Storage::Disk;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user