1
0
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:
Thomas Harte 2016-11-21 20:47:16 +08:00
parent 31c2548804
commit 8499783b14
11 changed files with 244 additions and 45 deletions

View File

@ -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 */,

View File

@ -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>

View File

@ -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

View File

@ -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)

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

View 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 */

View File

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

View File

@ -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_;
};

View File

@ -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_))

View 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

View File

@ -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)