mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +00:00
Dragged multibyte primitives and signature checks up to the base class. Implemented support for Oric MFM-style .DSK, at the file format level.
This commit is contained in:
parent
31c2548804
commit
8499783b14
@ -54,6 +54,7 @@
|
||||
4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B59199A1DAC6C46005BB85C /* OricTAP.cpp */; };
|
||||
4B5A12571DD55862007A2231 /* Disassembler6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A12551DD55862007A2231 /* Disassembler6502.cpp */; };
|
||||
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; };
|
||||
4B5FADBD1DE31D1500AEC565 /* OricMFMDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBB1DE31D1500AEC565 /* OricMFMDSK.cpp */; };
|
||||
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */; };
|
||||
4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; };
|
||||
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; };
|
||||
@ -502,6 +503,8 @@
|
||||
4B5A12561DD55862007A2231 /* Disassembler6502.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Disassembler6502.hpp; path = ../../StaticAnalyser/Disassembler/Disassembler6502.hpp; sourceTree = "<group>"; };
|
||||
4B5FADB81DE3151600AEC565 /* FileHolder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileHolder.cpp; sourceTree = "<group>"; };
|
||||
4B5FADB91DE3151600AEC565 /* FileHolder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileHolder.hpp; sourceTree = "<group>"; };
|
||||
4B5FADBB1DE31D1500AEC565 /* OricMFMDSK.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OricMFMDSK.cpp; sourceTree = "<group>"; };
|
||||
4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OricMFMDSK.hpp; sourceTree = "<group>"; };
|
||||
4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = "<group>"; };
|
||||
4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSStaticAnalyser.mm; path = StaticAnalyser/CSStaticAnalyser.mm; sourceTree = "<group>"; };
|
||||
4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Target.h"; sourceTree = "<group>"; };
|
||||
@ -1280,14 +1283,16 @@
|
||||
4BAB62B21D327F7E00DF5BA0 /* Formats */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BAB62B31D327F7E00DF5BA0 /* G64.cpp */,
|
||||
4BAB62B41D327F7E00DF5BA0 /* G64.hpp */,
|
||||
4B4C836E1D4F623200CD541F /* D64.cpp */,
|
||||
4B4C836F1D4F623200CD541F /* D64.hpp */,
|
||||
4BF829611D8F536B001BAE39 /* SSD.cpp */,
|
||||
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
||||
4BD69F921D98760000243FE1 /* AcornADF.cpp */,
|
||||
4BD69F931D98760000243FE1 /* AcornADF.hpp */,
|
||||
4B4C836E1D4F623200CD541F /* D64.cpp */,
|
||||
4B4C836F1D4F623200CD541F /* D64.hpp */,
|
||||
4BAB62B31D327F7E00DF5BA0 /* G64.cpp */,
|
||||
4BAB62B41D327F7E00DF5BA0 /* G64.hpp */,
|
||||
4B5FADBB1DE31D1500AEC565 /* OricMFMDSK.cpp */,
|
||||
4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */,
|
||||
4BF829611D8F536B001BAE39 /* SSD.cpp */,
|
||||
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
||||
);
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
@ -2333,6 +2338,7 @@
|
||||
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,
|
||||
4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */,
|
||||
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */,
|
||||
4B5FADBD1DE31D1500AEC565 /* OricMFMDSK.cpp in Sources */,
|
||||
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
|
||||
4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */,
|
||||
4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */,
|
||||
|
@ -49,7 +49,7 @@
|
||||
<string>rom</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Electron/BBC ROM Image</string>
|
||||
<string>ROM Image</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
@ -146,6 +146,18 @@
|
||||
<key>NSDocumentClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>dsk</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Disk Image</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>NSDocumentClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "../Storage/Disk/Formats/AcornADF.hpp"
|
||||
#include "../Storage/Disk/Formats/D64.hpp"
|
||||
#include "../Storage/Disk/Formats/G64.hpp"
|
||||
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
||||
#include "../Storage/Disk/Formats/SSD.hpp"
|
||||
|
||||
// Tapes
|
||||
@ -88,6 +89,7 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name)
|
||||
Format("bin", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // BIN
|
||||
Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64
|
||||
Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD
|
||||
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK
|
||||
Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64
|
||||
|
||||
// PRG
|
||||
|
@ -18,11 +18,7 @@ G64::G64(const char *file_name) :
|
||||
Storage::FileHolder(file_name)
|
||||
{
|
||||
// read and check the file signature
|
||||
char signature[8];
|
||||
if(fread(signature, 1, 8, file_) != 8)
|
||||
throw ErrorNotG64;
|
||||
|
||||
if(memcmp(signature, "GCR-1541", 8))
|
||||
if(!check_signature("GCR-1541", 8))
|
||||
throw ErrorNotG64;
|
||||
|
||||
// check the version number
|
||||
@ -34,8 +30,7 @@ G64::G64(const char *file_name) :
|
||||
|
||||
// get the number of tracks and track size
|
||||
number_of_tracks_ = (uint8_t)fgetc(file_);
|
||||
maximum_track_size_ = (uint16_t)fgetc(file_);
|
||||
maximum_track_size_ |= (uint16_t)fgetc(file_) << 8;
|
||||
maximum_track_size_ = fgetc16le();
|
||||
}
|
||||
|
||||
unsigned int G64::get_head_position_count()
|
||||
@ -59,10 +54,7 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int head, unsigned in
|
||||
|
||||
// read the track offset
|
||||
uint32_t track_offset;
|
||||
track_offset = (uint32_t)fgetc(file_);
|
||||
track_offset |= (uint32_t)fgetc(file_) << 8;
|
||||
track_offset |= (uint32_t)fgetc(file_) << 16;
|
||||
track_offset |= (uint32_t)fgetc(file_) << 24;
|
||||
track_offset = fgetc32le();
|
||||
|
||||
// if the track offset is zero, this track doesn't exist, so...
|
||||
if(!track_offset) return resulting_track;
|
||||
@ -72,8 +64,7 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int head, unsigned in
|
||||
|
||||
// get the real track length
|
||||
uint16_t track_length;
|
||||
track_length = (uint16_t)fgetc(file_);
|
||||
track_length |= (uint16_t)fgetc(file_) << 8;
|
||||
track_length = fgetc16le();
|
||||
|
||||
// grab the byte contents of this track
|
||||
std::vector<uint8_t> track_contents(track_length);
|
||||
@ -84,10 +75,7 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int head, unsigned in
|
||||
|
||||
// read the speed zone offsrt
|
||||
uint32_t speed_zone_offset;
|
||||
speed_zone_offset = (uint32_t)fgetc(file_);
|
||||
speed_zone_offset |= (uint32_t)fgetc(file_) << 8;
|
||||
speed_zone_offset |= (uint32_t)fgetc(file_) << 16;
|
||||
speed_zone_offset |= (uint32_t)fgetc(file_) << 24;
|
||||
speed_zone_offset = fgetc32le();
|
||||
|
||||
// if the speed zone is not constant, create a track based on the whole table; otherwise create one that's constant
|
||||
if(speed_zone_offset > 3)
|
||||
|
59
Storage/Disk/Formats/OricMFMDSK.cpp
Normal file
59
Storage/Disk/Formats/OricMFMDSK.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// OricMFMDSK.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 21/11/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "OricMFMDSK.hpp"
|
||||
#include "../PCMTrack.hpp"
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
OricMFMDSK::OricMFMDSK(const char *file_name) :
|
||||
Storage::FileHolder(file_name)
|
||||
{
|
||||
if(!check_signature("MFM_DISK", 8))
|
||||
throw ErrorNotOricMFMDSK;
|
||||
|
||||
head_count_ = fgetc32le();
|
||||
track_count_ = fgetc32le();
|
||||
geometry_type_ = fgetc32le();
|
||||
|
||||
if(geometry_type_ > 1)
|
||||
throw ErrorNotOricMFMDSK;
|
||||
}
|
||||
|
||||
unsigned int OricMFMDSK::get_head_position_count()
|
||||
{
|
||||
return track_count_;
|
||||
}
|
||||
|
||||
unsigned int OricMFMDSK::get_head_count()
|
||||
{
|
||||
return head_count_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> OricMFMDSK::get_track_at_position(unsigned int head, unsigned int position)
|
||||
{
|
||||
long offset = 0;
|
||||
switch(geometry_type_)
|
||||
{
|
||||
case 0:
|
||||
offset = (head * track_count_) + position;
|
||||
break;
|
||||
case 1:
|
||||
offset = (position * track_count_ * head_count_) + head;
|
||||
break;
|
||||
}
|
||||
fseek(file_, (offset * 6400) + 256, SEEK_SET);
|
||||
|
||||
PCMSegment segment;
|
||||
segment.number_of_bits = 6250*8;
|
||||
segment.data.resize(6250);
|
||||
fread(segment.data.data(), 1, 6250, file_);
|
||||
|
||||
std::shared_ptr<PCMTrack> track(new PCMTrack(segment));
|
||||
return track;
|
||||
}
|
49
Storage/Disk/Formats/OricMFMDSK.hpp
Normal file
49
Storage/Disk/Formats/OricMFMDSK.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// OricMFMDSK.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 21/11/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef OricMFMDSK_hpp
|
||||
#define OricMFMDSK_hpp
|
||||
|
||||
#include "../Disk.hpp"
|
||||
#include "../../FileHolder.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
|
||||
/*!
|
||||
Provies a @c Disk containing an Oric MFM-stype disk image — an MFM bit stream.
|
||||
*/
|
||||
class OricMFMDSK: 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.
|
||||
*/
|
||||
OricMFMDSK(const char *file_name);
|
||||
|
||||
enum {
|
||||
ErrorNotOricMFMDSK,
|
||||
};
|
||||
|
||||
// implemented to satisfy @c Disk
|
||||
unsigned int get_head_position_count();
|
||||
unsigned int get_head_count();
|
||||
std::shared_ptr<Track> get_track_at_position(unsigned int head, unsigned int position);
|
||||
|
||||
private:
|
||||
uint32_t head_count_;
|
||||
uint32_t track_count_;
|
||||
uint32_t geometry_type_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* OricMFMDSK_hpp */
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "FileHolder.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace Storage;
|
||||
|
||||
FileHolder::~FileHolder()
|
||||
@ -21,3 +23,59 @@ FileHolder::FileHolder(const char *file_name) : file_(nullptr)
|
||||
file_ = fopen(file_name, "rb");
|
||||
if(!file_) throw ErrorCantOpen;
|
||||
}
|
||||
|
||||
bool FileHolder::check_signature(const char *signature, size_t length)
|
||||
{
|
||||
if(!length) length = strlen(signature)+1;
|
||||
|
||||
// read and check the file signature
|
||||
char stored_signature[12];
|
||||
if(fread(stored_signature, 1, length, file_) != length) return false;
|
||||
if(memcmp(stored_signature, signature, length)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t FileHolder::fgetc32le()
|
||||
{
|
||||
uint32_t result = (uint32_t)fgetc(file_);
|
||||
result |= (uint32_t)(fgetc(file_) << 8);
|
||||
result |= (uint32_t)(fgetc(file_) << 16);
|
||||
result |= (uint32_t)(fgetc(file_) << 24);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FileHolder::fgetc24le()
|
||||
{
|
||||
uint32_t result = (uint32_t)fgetc(file_);
|
||||
result |= (uint32_t)(fgetc(file_) << 8);
|
||||
result |= (uint32_t)(fgetc(file_) << 16);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t FileHolder::fgetc16le()
|
||||
{
|
||||
uint16_t result = (uint16_t)fgetc(file_);
|
||||
result |= (uint16_t)(fgetc(file_) << 8);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t FileHolder::fgetc32be()
|
||||
{
|
||||
uint32_t result = (uint32_t)(fgetc(file_) << 24);
|
||||
result |= (uint32_t)(fgetc(file_) << 16);
|
||||
result |= (uint32_t)(fgetc(file_) << 8);
|
||||
result |= (uint32_t)fgetc(file_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t FileHolder::fgetc16be()
|
||||
{
|
||||
uint16_t result = (uint16_t)(fgetc(file_) << 8);
|
||||
result |= (uint16_t)fgetc(file_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Storage {
|
||||
|
||||
@ -25,6 +26,45 @@ class FileHolder {
|
||||
protected:
|
||||
FileHolder(const char *file_name);
|
||||
|
||||
/*!
|
||||
Reads @c length bytes from the file and compares them to the first
|
||||
@c length bytes of @c signature. If @c length is 0, it is computed
|
||||
as the length of @c signature up to and including the terminating null.
|
||||
|
||||
@returns @c true if the bytes read match the signature; @c false otherwise.
|
||||
*/
|
||||
bool check_signature(const char *signature, size_t length);
|
||||
|
||||
/*!
|
||||
Performs @c fgetc four times on @c file_, casting each result to a @c uint32_t
|
||||
and returning the four assembled in little endian order.
|
||||
*/
|
||||
uint32_t fgetc32le();
|
||||
|
||||
/*!
|
||||
Performs @c fgetc three times on @c file_, casting each result to a @c uint32_t
|
||||
and returning the three assembled in little endian order.
|
||||
*/
|
||||
uint32_t fgetc24le();
|
||||
|
||||
/*!
|
||||
Performs @c fgetc two times on @c file_, casting each result to a @c uint32_t
|
||||
and returning the two assembled in little endian order.
|
||||
*/
|
||||
uint16_t fgetc16le();
|
||||
|
||||
/*!
|
||||
Performs @c fgetc four times on @c file_, casting each result to a @c uint32_t
|
||||
and returning the four assembled in big endian order.
|
||||
*/
|
||||
uint32_t fgetc32be();
|
||||
|
||||
/*!
|
||||
Performs @c fgetc two times on @c file_, casting each result to a @c uint32_t
|
||||
and returning the two assembled in big endian order.
|
||||
*/
|
||||
uint16_t fgetc16be();
|
||||
|
||||
FILE *file_;
|
||||
struct stat file_stats_;
|
||||
};
|
||||
|
@ -16,12 +16,7 @@ CommodoreTAP::CommodoreTAP(const char *file_name) :
|
||||
is_at_end_(false),
|
||||
Storage::FileHolder(file_name)
|
||||
{
|
||||
// read and check the file signature
|
||||
char signature[12];
|
||||
if(fread(signature, 1, 12, file_) != 12)
|
||||
throw ErrorNotCommodoreTAP;
|
||||
|
||||
if(memcmp(signature, "C64-TAPE-RAW", 12))
|
||||
if(!check_signature("C64-TAPE-RAW", 12))
|
||||
throw ErrorNotCommodoreTAP;
|
||||
|
||||
// check the file version
|
||||
@ -37,10 +32,7 @@ CommodoreTAP::CommodoreTAP(const char *file_name) :
|
||||
fseek(file_, 3, SEEK_CUR);
|
||||
|
||||
// read file size
|
||||
file_size_ = (uint32_t)fgetc(file_);
|
||||
file_size_ |= (uint32_t)(fgetc(file_) << 8);
|
||||
file_size_ |= (uint32_t)(fgetc(file_) << 16);
|
||||
file_size_ |= (uint32_t)(fgetc(file_) << 24);
|
||||
file_size_ = fgetc32le();
|
||||
|
||||
// set up for pulse output at the PAL clock rate, with each high and
|
||||
// low being half of whatever length values will be read; pretend that
|
||||
@ -79,9 +71,7 @@ Storage::Tape::Tape::Pulse CommodoreTAP::virtual_get_next_pulse()
|
||||
}
|
||||
else
|
||||
{
|
||||
next_length = (uint32_t)fgetc(file_);
|
||||
next_length |= (uint32_t)(fgetc(file_) << 8);
|
||||
next_length |= (uint32_t)(fgetc(file_) << 16);
|
||||
next_length = fgetc24le();
|
||||
}
|
||||
|
||||
if(feof(file_))
|
||||
|
@ -15,12 +15,8 @@ using namespace Storage::Tape;
|
||||
OricTAP::OricTAP(const char *file_name) :
|
||||
Storage::FileHolder(file_name)
|
||||
{
|
||||
// read and check the file signature
|
||||
uint8_t signature[4];
|
||||
if(fread(signature, 1, 4, file_) != 4)
|
||||
throw ErrorNotOricTAP;
|
||||
|
||||
if(signature[0] != 0x16 || signature[1] != 0x16 || signature[2] != 0x16 || signature[3] != 0x24)
|
||||
// check the file signature
|
||||
if(!check_signature("\x16\x16\x16\x24", 4))
|
||||
throw ErrorNotOricTAP;
|
||||
|
||||
// then rewind and start again
|
||||
|
@ -60,8 +60,7 @@ PRG::PRG(const char *file_name) :
|
||||
if(file_stats_.st_size >= 65538 || file_stats_.st_size < 3)
|
||||
throw ErrorBadFormat;
|
||||
|
||||
load_address_ = (uint16_t)fgetc(file_);
|
||||
load_address_ |= (uint16_t)fgetc(file_) << 8;
|
||||
load_address_ = fgetc16le();
|
||||
length_ = (uint16_t)(file_stats_.st_size - 2);
|
||||
|
||||
if (load_address_ + length_ >= 65536)
|
||||
|
Loading…
x
Reference in New Issue
Block a user