mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-08 14:25:05 +00:00
Merge branch 'master' into Memptr
This commit is contained in:
@@ -184,6 +184,7 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>p</string>
|
<string>p</string>
|
||||||
<string>81</string>
|
<string>81</string>
|
||||||
|
<string>p81</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeIconFile</key>
|
<key>CFBundleTypeIconFile</key>
|
||||||
<string>cassette</string>
|
<string>cassette</string>
|
||||||
|
@@ -104,7 +104,8 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name)
|
|||||||
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK
|
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK
|
||||||
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) // O
|
Format("p", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||||
|
Format("p81", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P81
|
||||||
|
|
||||||
// PRG
|
// PRG
|
||||||
if(!strcmp(lowercase_extension, "prg"))
|
if(!strcmp(lowercase_extension, "prg"))
|
||||||
|
@@ -12,26 +12,22 @@
|
|||||||
|
|
||||||
using namespace Storage;
|
using namespace Storage;
|
||||||
|
|
||||||
FileHolder::~FileHolder()
|
FileHolder::~FileHolder() {
|
||||||
{
|
|
||||||
if(file_) fclose(file_);
|
if(file_) fclose(file_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHolder::FileHolder(const char *file_name) : file_(nullptr)
|
FileHolder::FileHolder(const std::string &file_name) : file_(nullptr), name_(file_name) {
|
||||||
{
|
stat(file_name.c_str(), &file_stats_);
|
||||||
stat(file_name, &file_stats_);
|
|
||||||
is_read_only_ = false;
|
is_read_only_ = false;
|
||||||
file_ = fopen(file_name, "rb+");
|
file_ = fopen(file_name.c_str(), "rb+");
|
||||||
if(!file_)
|
if(!file_) {
|
||||||
{
|
|
||||||
is_read_only_ = true;
|
is_read_only_ = true;
|
||||||
file_ = fopen(file_name, "rb");
|
file_ = fopen(file_name.c_str(), "rb");
|
||||||
}
|
}
|
||||||
if(!file_) throw ErrorCantOpen;
|
if(!file_) throw ErrorCantOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileHolder::check_signature(const char *signature, size_t length)
|
bool FileHolder::check_signature(const char *signature, size_t length) {
|
||||||
{
|
|
||||||
if(!length) length = strlen(signature)+1;
|
if(!length) length = strlen(signature)+1;
|
||||||
|
|
||||||
// read and check the file signature
|
// read and check the file signature
|
||||||
@@ -41,8 +37,7 @@ bool FileHolder::check_signature(const char *signature, size_t length)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FileHolder::fgetc32le()
|
uint32_t FileHolder::fgetc32le() {
|
||||||
{
|
|
||||||
uint32_t result = (uint32_t)fgetc(file_);
|
uint32_t result = (uint32_t)fgetc(file_);
|
||||||
result |= (uint32_t)(fgetc(file_) << 8);
|
result |= (uint32_t)(fgetc(file_) << 8);
|
||||||
result |= (uint32_t)(fgetc(file_) << 16);
|
result |= (uint32_t)(fgetc(file_) << 16);
|
||||||
@@ -51,8 +46,7 @@ uint32_t FileHolder::fgetc32le()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FileHolder::fgetc24le()
|
uint32_t FileHolder::fgetc24le() {
|
||||||
{
|
|
||||||
uint32_t result = (uint32_t)fgetc(file_);
|
uint32_t result = (uint32_t)fgetc(file_);
|
||||||
result |= (uint32_t)(fgetc(file_) << 8);
|
result |= (uint32_t)(fgetc(file_) << 8);
|
||||||
result |= (uint32_t)(fgetc(file_) << 16);
|
result |= (uint32_t)(fgetc(file_) << 16);
|
||||||
@@ -60,16 +54,14 @@ uint32_t FileHolder::fgetc24le()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t FileHolder::fgetc16le()
|
uint16_t FileHolder::fgetc16le() {
|
||||||
{
|
|
||||||
uint16_t result = (uint16_t)fgetc(file_);
|
uint16_t result = (uint16_t)fgetc(file_);
|
||||||
result |= (uint16_t)(fgetc(file_) << 8);
|
result |= (uint16_t)(fgetc(file_) << 8);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FileHolder::fgetc32be()
|
uint32_t FileHolder::fgetc32be() {
|
||||||
{
|
|
||||||
uint32_t result = (uint32_t)(fgetc(file_) << 24);
|
uint32_t result = (uint32_t)(fgetc(file_) << 24);
|
||||||
result |= (uint32_t)(fgetc(file_) << 16);
|
result |= (uint32_t)(fgetc(file_) << 16);
|
||||||
result |= (uint32_t)(fgetc(file_) << 8);
|
result |= (uint32_t)(fgetc(file_) << 8);
|
||||||
@@ -78,16 +70,14 @@ uint32_t FileHolder::fgetc32be()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t FileHolder::fgetc16be()
|
uint16_t FileHolder::fgetc16be() {
|
||||||
{
|
|
||||||
uint16_t result = (uint16_t)(fgetc(file_) << 8);
|
uint16_t result = (uint16_t)(fgetc(file_) << 8);
|
||||||
result |= (uint16_t)fgetc(file_);
|
result |= (uint16_t)fgetc(file_);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileHolder::ensure_file_is_at_least_length(long length)
|
void FileHolder::ensure_file_is_at_least_length(long length) {
|
||||||
{
|
|
||||||
fseek(file_, 0, SEEK_END);
|
fseek(file_, 0, SEEK_END);
|
||||||
long bytes_to_write = length - ftell(file_);
|
long bytes_to_write = length - ftell(file_);
|
||||||
if(bytes_to_write > 0)
|
if(bytes_to_write > 0)
|
||||||
@@ -98,3 +88,13 @@ void FileHolder::ensure_file_is_at_least_length(long length)
|
|||||||
delete[] empty;
|
delete[] empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string FileHolder::extension() {
|
||||||
|
size_t pointer = name_.size() - 1;
|
||||||
|
while(pointer > 0 && name_[pointer] != '.') pointer--;
|
||||||
|
if(name_[pointer] == '.') pointer++;
|
||||||
|
|
||||||
|
std::string extension = name_.substr(pointer);
|
||||||
|
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace Storage {
|
namespace Storage {
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ class FileHolder {
|
|||||||
virtual ~FileHolder();
|
virtual ~FileHolder();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileHolder(const char *file_name);
|
FileHolder(const std::string &file_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Reads @c length bytes from the file and compares them to the first
|
Reads @c length bytes from the file and compares them to the first
|
||||||
@@ -65,6 +66,12 @@ class FileHolder {
|
|||||||
*/
|
*/
|
||||||
uint16_t fgetc16be();
|
uint16_t fgetc16be();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines and returns the file extension — everything from the final character
|
||||||
|
back to the first dot. The string is converted to lowercase before being returned.
|
||||||
|
*/
|
||||||
|
std::string extension();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Ensures the file is at least @c length bytes long, appending 0s until it is
|
Ensures the file is at least @c length bytes long, appending 0s until it is
|
||||||
if necessary.
|
if necessary.
|
||||||
@@ -117,6 +124,8 @@ class FileHolder {
|
|||||||
FILE *file_;
|
FILE *file_;
|
||||||
struct stat file_stats_;
|
struct stat file_stats_;
|
||||||
bool is_read_only_;
|
bool is_read_only_;
|
||||||
|
|
||||||
|
const std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,8 @@ ZX80O81P::ZX80O81P(const char *file_name) :
|
|||||||
fread(data_.data(), 1, (size_t)file_stats_.st_size, file_);
|
fread(data_.data(), 1, (size_t)file_stats_.st_size, file_);
|
||||||
|
|
||||||
// If it's a ZX81 file, prepend a file name.
|
// If it's a ZX81 file, prepend a file name.
|
||||||
char type = (char)tolower(file_name[strlen(file_name) - 1]);
|
std::string type = extension();
|
||||||
if(type == 'p' || type == '1') {
|
if(type == "p" || type == "81") {
|
||||||
// TODO, maybe: prefix a proper file name; this is leaving the file nameless.
|
// TODO, maybe: prefix a proper file name; this is leaving the file nameless.
|
||||||
data_.insert(data_.begin(), 0x80);
|
data_.insert(data_.begin(), 0x80);
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ template <typename SymbolType> class Parser {
|
|||||||
while(!has_next_symbol_ && !tape->is_at_end()) {
|
while(!has_next_symbol_ && !tape->is_at_end()) {
|
||||||
process_pulse(tape->get_next_pulse());
|
process_pulse(tape->get_next_pulse());
|
||||||
}
|
}
|
||||||
if(tape->is_at_end()) mark_end();
|
if(!has_next_symbol_ && tape->is_at_end()) mark_end();
|
||||||
has_next_symbol_ = false;
|
has_next_symbol_ = false;
|
||||||
return next_symbol_;
|
return next_symbol_;
|
||||||
}
|
}
|
||||||
|
@@ -45,10 +45,8 @@ void Parser::post_pulse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Parser::mark_end() {
|
void Parser::mark_end() {
|
||||||
// Push the last thing detected, and post an 'unrecognised' to ensure
|
// Post a long gap to cap any bit that's in the process of recognition.
|
||||||
// the queue empties out.
|
push_wave(WaveType::LongGap);
|
||||||
post_pulse();
|
|
||||||
push_wave(WaveType::Unrecognised);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::inspect_waves(const std::vector<WaveType> &waves) {
|
void Parser::inspect_waves(const std::vector<WaveType> &waves) {
|
||||||
@@ -76,14 +74,11 @@ void Parser::inspect_waves(const std::vector<WaveType> &waves) {
|
|||||||
number_of_pulses++;
|
number_of_pulses++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If those pulses were followed by a gap then they might be
|
// If those pulses were followed by something not recognised as a pulse, check for a bit
|
||||||
// a recognised symbol.
|
if(number_of_pulses + wave_offset < waves.size()) {
|
||||||
if(number_of_pulses + wave_offset < waves.size() &&
|
// A 1 is 9 waves, a 0 is 4. Counting upward zero transitions, the first in either group will
|
||||||
(waves[number_of_pulses + wave_offset] == WaveType::LongGap || waves[number_of_pulses + wave_offset] == WaveType::Gap)) {
|
// act simply to terminate the gap beforehand and won't be logged as a pulse. So counts to
|
||||||
// A 1 is 18 up/down waves, a 0 is 8. But the final down will be indistinguishable from
|
// check are 8 and 3.
|
||||||
// the gap that follows the bit due to the simplified "high is high, everything else is low"
|
|
||||||
// logic applied to pulse detection. So those two things will merge. Meaning we're looking for
|
|
||||||
// 17 and/or 7 pulses.
|
|
||||||
size_t gaps_to_swallow = wave_offset + ((waves[number_of_pulses + wave_offset] == WaveType::Gap) ? 1 : 0);
|
size_t gaps_to_swallow = wave_offset + ((waves[number_of_pulses + wave_offset] == WaveType::Gap) ? 1 : 0);
|
||||||
switch(number_of_pulses) {
|
switch(number_of_pulses) {
|
||||||
case 8: push_symbol(SymbolType::One, (int)(number_of_pulses + gaps_to_swallow)); break;
|
case 8: push_symbol(SymbolType::One, (int)(number_of_pulses + gaps_to_swallow)); break;
|
||||||
|
Reference in New Issue
Block a user