1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-04-22 09:37:21 +00:00

Template away repetition.

This commit is contained in:
Thomas Harte 2025-02-18 22:48:47 -05:00
parent f786f8a970
commit edd4ed307f
23 changed files with 207 additions and 282 deletions

View File

@ -34,17 +34,17 @@ Disk2MG::DiskOrMassStorageDevice Disk2MG::open(const std::string &file_name) {
const auto creator = file.read(4);
// Grab the header size, version number and image format.
const uint16_t header_size = file.get16le();
const uint16_t version = file.get16le();
const uint32_t format = file.get32le();
const uint32_t flags = file.get32le();
const uint16_t header_size = file.get_le<uint16_t>();
const uint16_t version = file.get_le<uint16_t>();
const uint32_t format = file.get_le<uint32_t>();
const uint32_t flags = file.get_le<uint32_t>();
// Skip the number of ProDOS blocks; this is surely implicit from the data size?
file.seek(4, SEEK_CUR);
// Get the offset and size of the disk image data.
const uint32_t data_start = file.get32le();
uint32_t data_size = file.get32le();
const uint32_t data_start = file.get_le<uint32_t>();
uint32_t data_size = file.get_le<uint32_t>();
// Correct for the Sweet 16 emulator, which writes broken 2MGs.
if(!data_size && !memcmp(creator.data(), "WOOF", 4)) {

View File

@ -48,7 +48,7 @@ CPCDSK::CPCDSK(const std::string &file_name) :
track_sizes.push_back(size_t(file.get8()) << 8);
}
} else {
size_of_a_track = file.get16le();
size_of_a_track = file.get_le<uint16_t>();
}
long file_offset = 0x100;
@ -140,7 +140,7 @@ CPCDSK::CPCDSK(const std::string &file_name) :
// sector was weak or fuzzy and that multiple samplings are provided. If the greater size
// is not an exact multiple then my reading of the documentation is that this is an invalid
// disk image.
std::size_t declared_data_size = file.get16le();
std::size_t declared_data_size = file.get_le<uint16_t>();
if(declared_data_size != stored_data_size) {
if(declared_data_size > data_size) {
number_of_samplings = declared_data_size / data_size;
@ -365,7 +365,7 @@ void CPCDSK::set_tracks(const std::map<::Storage::Disk::Track::Address, std::uni
for(auto &sample: sector.samples) {
data_size += sample.size();
}
output.put16le(uint16_t(data_size));
output.put_le<uint16_t>(uint16_t(data_size));
}
// Move to next 256-byte boundary.

View File

@ -42,7 +42,7 @@ DMK::DMK(const std::string &file_name) :
// Read track count and size.
head_position_count_ = int(file_.get8());
track_length_ = long(file_.get16le());
track_length_ = long(file_.get_le<uint16_t>());
// Track length must be at least 0x80, as that's the size of the IDAM
// table before track contents.
@ -57,7 +57,7 @@ DMK::DMK(const std::string &file_name) :
// Skip to the end of the header and check that this is
// "in the emulator's native format".
file_.seek(0xc, SEEK_SET);
uint32_t format = file_.get32le();
uint32_t format = file_.get_le<uint32_t>();
if(format) throw Error::InvalidFormat;
}
@ -86,7 +86,7 @@ std::unique_ptr<::Storage::Disk::Track> DMK::track_at_position(::Storage::Disk::
uint16_t idam_locations[64];
std::size_t idam_count = 0;
for(std::size_t c = 0; c < sizeof(idam_locations) / sizeof(*idam_locations); ++c) {
idam_locations[idam_count] = file_.get16le();
idam_locations[idam_count] = file_.get_le<uint16_t>();
if((idam_locations[idam_count] & 0x7fff) >= 128) {
idam_count++;
}

View File

@ -22,12 +22,12 @@ FAT12::FAT12(const std::string &file_name) :
// Inspect the FAT.
file_.seek(11, SEEK_SET);
sector_size_ = file_.get16le();
sector_size_ = file_.get_le<uint16_t>();
file_.seek(19, SEEK_SET);
const uint16_t total_sectors = file_.get16le();
const uint16_t total_sectors = file_.get_le<uint16_t>();
file_.seek(24, SEEK_SET);
sector_count_ = file_.get16le();
head_count_ = file_.get16le();
sector_count_ = file_.get_le<uint16_t>();
head_count_ = file_.get_le<uint16_t>();
// Throw if there would seemingly be an incomplete track.
if(file_size != total_sectors*sector_size_) throw Error::InvalidFormat;

View File

@ -27,7 +27,7 @@ G64::G64(const std::string &file_name) :
// get the number of tracks and track size
number_of_tracks_ = file_.get8();
maximum_track_size_ = file_.get16le();
maximum_track_size_ = file_.get_le<uint16_t>();
}
HeadPosition G64::get_maximum_head_position() {
@ -41,7 +41,7 @@ std::unique_ptr<Track> G64::track_at_position(Track::Address address) {
file_.seek(long((address.position.as_half() * 4) + 0xc), SEEK_SET);
// read the track offset
const uint32_t track_offset = file_.get32le();
const uint32_t track_offset = file_.get_le<uint32_t>();
// if the track offset is zero, this track doesn't exist, so...
if(!track_offset) return nullptr;
@ -50,7 +50,7 @@ std::unique_ptr<Track> G64::track_at_position(Track::Address address) {
file_.seek(long(track_offset), SEEK_SET);
// get the real track length
const uint16_t track_length = file_.get16le();
const uint16_t track_length = file_.get_le<uint16_t>();
// grab the byte contents of this track
const std::vector<uint8_t> track_contents = file_.read(track_length);
@ -59,7 +59,7 @@ std::unique_ptr<Track> G64::track_at_position(Track::Address address) {
file_.seek(long((address.position.as_half() * 4) + 0x15c), SEEK_SET);
// read the speed zone offsrt
const uint32_t speed_zone_offset = file_.get32le();
const uint32_t speed_zone_offset = file_.get_le<uint32_t>();
// 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

@ -22,7 +22,7 @@ HFE::HFE(const std::string &file_name) :
head_count_ = file_.get8();
file_.seek(7, SEEK_CUR);
track_list_offset_ = long(file_.get16le()) << 9;
track_list_offset_ = long(file_.get_le<uint16_t>()) << 9;
}
HeadPosition HFE::get_maximum_head_position() {
@ -45,8 +45,8 @@ uint16_t HFE::seek_track(Track::Address address) {
// based on an assumption of two heads.
file_.seek(track_list_offset_ + address.position.as_int() * 4, SEEK_SET);
long track_offset = long(file_.get16le()) << 9; // Track offset, in units of 512 bytes.
uint16_t track_length = file_.get16le(); // Track length, in bytes, containing both the front and back track.
long track_offset = long(file_.get_le<uint16_t>()) << 9; // Track offset, in units of 512 bytes.
uint16_t track_length = file_.get_le<uint16_t>(); // Track length, in bytes, containing both the front and back track.
file_.seek(track_offset, SEEK_SET);
if(address.head) file_.seek(256, SEEK_CUR);

View File

@ -43,9 +43,9 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
// plus the other fields that'll be necessary to convert them into flux on demand later.
while(true) {
const auto start_of_block = file_.tell();
const uint32_t type = file_.get32be();
uint32_t length = file_.get32be(); // Can't be const because of the dumb encoding of DATA blocks.
[[maybe_unused]] const uint32_t crc = file_.get32be();
const uint32_t type = file_.get_be<uint32_t>();
uint32_t length = file_.get_be<uint32_t>(); // Can't be const because of the dumb encoding of DATA blocks.
[[maybe_unused]] const uint32_t crc = file_.get_be<uint32_t>();
if(file_.eof()) break;
// Sanity check: the first thing in a file should be the CAPS record.
@ -71,21 +71,21 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
// aren't that interesting.
// Make sure this is a floppy disk.
const uint32_t media_type = file_.get32be();
const uint32_t media_type = file_.get_be<uint32_t>();
if(media_type != 1) {
throw Error::InvalidFormat;
}
// Determine whether this is a newer SPS-style file.
is_sps_format_ = file_.get32be() > 1;
is_sps_format_ = file_.get_be<uint32_t>() > 1;
// Skip: revision, file key and revision, CRC of the original .ctr, and minimum track.
file_.seek(20, SEEK_CUR);
track_count_ = int(1 + file_.get32be());
track_count_ = int(1 + file_.get_be<uint32_t>());
// Skip: min side.
file_.seek(4, SEEK_CUR);
head_count_ = int(1 + file_.get32be());
head_count_ = int(1 + file_.get_be<uint32_t>());
// Skip: creation date, time.
file_.seek(8, SEEK_CUR);
@ -117,8 +117,8 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
case block("IMGE"): {
// Get track location.
const uint32_t track = file_.get32be();
const uint32_t side = file_.get32be();
const uint32_t track = file_.get_be<uint32_t>();
const uint32_t side = file_.get_be<uint32_t>();
const Track::Address address{int(side), HeadPosition(int(track))};
// Hence generate a TrackDescription.
@ -128,31 +128,31 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
// Read those fields of interest...
// Bit density. I've no idea why the density can't just be given as a measurement.
description.density = TrackDescription::Density(file_.get32be());
description.density = TrackDescription::Density(file_.get_be<uint32_t>());
if(description.density > TrackDescription::Density::Max) {
description.density = TrackDescription::Density::Unknown;
}
file_.seek(12, SEEK_CUR); // Skipped: signal type, track bytes, start byte position.
description.start_bit_pos = file_.get32be();
description.data_bits = file_.get32be();
description.gap_bits = file_.get32be();
description.start_bit_pos = file_.get_be<uint32_t>();
description.data_bits = file_.get_be<uint32_t>();
description.gap_bits = file_.get_be<uint32_t>();
file_.seek(4, SEEK_CUR); // Skipped: track bits, which is entirely redundant.
description.block_count = file_.get32be();
description.block_count = file_.get_be<uint32_t>();
file_.seek(4, SEEK_CUR); // Skipped: encoder process.
description.has_fuzzy_bits = file_.get32be() & 1;
description.has_fuzzy_bits = file_.get_be<uint32_t>() & 1;
// For some reason the authors decided to introduce another primary key,
// in addition to that which naturally exists of (track, side). So set up
// a mapping from the one to the other.
const uint32_t data_key = file_.get32be();
const uint32_t data_key = file_.get_be<uint32_t>();
tracks_by_data_key.emplace(data_key, address);
} break;
case block("DATA"): {
length += file_.get32be();
length += file_.get_be<uint32_t>();
file_.seek(8, SEEK_CUR); // Skipped: bit size, CRC.
@ -160,7 +160,7 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
// position for this track.
//
// Assumed here: DATA records will come after corresponding IMGE records.
const uint32_t data_key = file_.get32be();
const uint32_t data_key = file_.get_be<uint32_t>();
const auto pair = tracks_by_data_key.find(data_key);
if(pair == tracks_by_data_key.end()) {
break;
@ -220,24 +220,24 @@ std::unique_ptr<Track> IPF::track_at_position([[maybe_unused]] Track::Address ad
blocks.reserve(description.block_count);
for(uint32_t c = 0; c < description.block_count; c++) {
auto &block = blocks.emplace_back();
block.data_bits = file_.get32be();
block.gap_bits = file_.get32be();
block.data_bits = file_.get_be<uint32_t>();
block.gap_bits = file_.get_be<uint32_t>();
if(is_sps_format_) {
block.gap_offset = file_.get32be();
block.gap_offset = file_.get_be<uint32_t>();
file_.seek(4, SEEK_CUR); // Skip 'cell type' which appears to provide no content.
} else {
// Skip potlower-resolution copies of data_bits and gap_bits.
file_.seek(8, SEEK_CUR);
}
block.is_mfm = file_.get32be() == 1;
block.is_mfm = file_.get_be<uint32_t>() == 1;
const uint32_t flags = file_.get32be();
const uint32_t flags = file_.get_be<uint32_t>();
block.has_forward_gap = flags & 1;
block.has_backwards_gap = flags & 2;
block.data_unit_is_bits = flags & 4;
block.default_gap_value = file_.get32be();
block.data_offset = file_.get32be();
block.default_gap_value = file_.get_be<uint32_t>();
block.data_offset = file_.get_be<uint32_t>();
}
std::vector<Storage::Disk::PCMSegment> segments;

View File

@ -16,17 +16,17 @@ using namespace Storage::Disk;
MSA::MSA(const std::string &file_name) :
file_(file_name) {
const auto signature = file_.get16be();
const auto signature = file_.get_be<uint16_t>();
if(signature != 0x0e0f) throw Error::InvalidFormat;
sectors_per_track_ = file_.get16be();
sides_ = 1 + file_.get16be();
starting_track_ = file_.get16be();
ending_track_ = file_.get16be();
sectors_per_track_ = file_.get_be<uint16_t>();
sides_ = 1 + file_.get_be<uint16_t>();
starting_track_ = file_.get_be<uint16_t>();
ending_track_ = file_.get_be<uint16_t>();
// Create the uncompressed track list.
while(true) {
const auto data_length = file_.get16be();
const auto data_length = file_.get_be<uint16_t>();
if(file_.eof()) break;
if(data_length == sectors_per_track_ * 512) {
@ -55,7 +55,7 @@ MSA::MSA(const std::string &file_name) :
if(pointer > data_length) break;
const auto value = file_.get8();
auto count = file_.get16be();
auto count = file_.get_be<uint16_t>();
while(count--) {
track.push_back(value);
}

View File

@ -67,10 +67,10 @@ MacintoshIMG::MacintoshIMG(const std::string &file_name) :
// Get the length of the data and tag blocks.
file_.seek(64, SEEK_SET);
const auto data_block_length = file_.get32be();
const auto tag_block_length = file_.get32be();
const auto data_checksum = file_.get32be();
const auto tag_checksum = file_.get32be();
const auto data_block_length = file_.get_be<uint32_t>();
const auto tag_block_length = file_.get_be<uint32_t>();
const auto data_checksum = file_.get_be<uint32_t>();
const auto tag_checksum = file_.get_be<uint32_t>();
// Don't continue with no data.
if(!data_block_length)
@ -89,7 +89,7 @@ MacintoshIMG::MacintoshIMG(const std::string &file_name) :
format_ = file_.get8();
// Check the magic number.
const auto magic_number = file_.get16be();
const auto magic_number = file_.get_be<uint16_t>();
if(magic_number != 0x0100)
throw Error::InvalidFormat;

View File

@ -21,9 +21,9 @@ OricMFMDSK::OricMFMDSK(const std::string &file_name) :
if(!file_.check_signature("MFM_DISK"))
throw Error::InvalidFormat;
head_count_ = file_.get32le();
track_count_ = file_.get32le();
geometry_type_ = file_.get32le();
head_count_ = file_.get_le<uint32_t>();
track_count_ = file_.get_le<uint32_t>();
geometry_type_ = file_.get_le<uint32_t>();
if(geometry_type_ < 1 || geometry_type_ > 2)
throw Error::InvalidFormat;

View File

@ -392,7 +392,7 @@ private:
STX::STX(const std::string &file_name) : file_(file_name) {
// Require that this be a version 3 Pasti.
if(!file_.check_signature("RSY", 4)) throw Error::InvalidFormat;
if(file_.get16le() != 3) throw Error::InvalidFormat;
if(file_.get_le<uint16_t>() != 3) throw Error::InvalidFormat;
// Skip: tool used, 2 reserved bytes.
file_.seek(4, SEEK_CUR);
@ -422,7 +422,7 @@ STX::STX(const std::string &file_name) : file_(file_name) {
head_count_ = 1;
while(true) {
const long offset = file_.tell();
const uint32_t size = file_.get32le();
const uint32_t size = file_.get_le<uint32_t>();
if(file_.eof()) break;
// Skip fields other than track position, then fill in table position and advance.
@ -460,10 +460,10 @@ std::unique_ptr<Track> STX::track_at_position(Track::Address address) {
file_.seek(offset_by_track_[track_index] + 4, SEEK_SET);
// Grab the track description.
const uint32_t fuzzy_size = file_.get32le();
const uint16_t sector_count = file_.get16le();
const uint16_t flags = file_.get16le();
const size_t track_length = file_.get16le();
const uint32_t fuzzy_size = file_.get_le<uint32_t>();
const uint16_t sector_count = file_.get_le<uint16_t>();
const uint16_t flags = file_.get_le<uint16_t>();
const size_t track_length = file_.get_le<uint16_t>();
file_.seek(2, SEEK_CUR); // Skip track type; despite being named, it's apparently unused.
// If this is a trivial .ST-style sector dump, life is easy.
@ -480,9 +480,9 @@ std::unique_ptr<Track> STX::track_at_position(Track::Address address) {
// Sector records come first.
for(uint16_t c = 0; c < sector_count; ++c) {
sectors.emplace_back();
sectors.back().data_offset = file_.get32le();
sectors.back().bit_position = file_.get16le();
sectors.back().data_duration = file_.get16le();
sectors.back().data_offset = file_.get_le<uint32_t>();
sectors.back().bit_position = file_.get_le<uint16_t>();
sectors.back().data_duration = file_.get_le<uint16_t>();
file_.read(sectors.back().address);
sectors.back().status = file_.get8();
file_.seek(1, SEEK_CUR);
@ -519,11 +519,11 @@ std::unique_ptr<Track> STX::track_at_position(Track::Address address) {
// Bit 6 => there is a track to read;
// bit
if(flags & 0x80) {
first_sync = file_.get16le();
const uint16_t image_size = file_.get16le();
first_sync = file_.get_le<uint16_t>();
const uint16_t image_size = file_.get_le<uint16_t>();
track_data = file_.read(image_size);
} else {
const uint16_t image_size = file_.get16le();
const uint16_t image_size = file_.get_le<uint16_t>();
track_data = file_.read(image_size);
}
}
@ -571,7 +571,7 @@ std::unique_ptr<Track> STX::track_at_position(Track::Address address) {
// This is going to be a new-format record.
for(size_t c = 0; c < timing_record_size; ++c) {
sector.timing[c] = file_.get16be(); // These values are big endian, unlike the rest of the file.
sector.timing[c] = file_.get_be<uint16_t>(); // These values are big endian, unlike the rest of the file.
}
}

View File

@ -41,7 +41,7 @@ WOZ::WOZ(const std::string &file_name) :
type_ = isWoz2 ? Type::WOZ2 : Type::WOZ1;
// Get the file's CRC32.
const uint32_t crc = file_.get32le();
const uint32_t crc = file_.get_le<uint32_t>();
// Get the collection of all data that contributes to the CRC.
post_crc_contents_ = file_.read(size_t(file_.stats().st_size - 12));
@ -58,8 +58,8 @@ WOZ::WOZ(const std::string &file_name) :
// Parse all chunks up front.
bool has_tmap = false;
while(true) {
const uint32_t chunk_id = file_.get32le();
const uint32_t chunk_size = file_.get32le();
const uint32_t chunk_id = file_.get_le<uint32_t>();
const uint32_t chunk_size = file_.get_le<uint32_t>();
if(file_.eof()) break;
long end_of_chunk = file_.tell() + long(chunk_size);
@ -167,15 +167,15 @@ std::unique_ptr<Track> WOZ::track_at_position(Track::Address address) {
// of bits that were used. Other information follows but is not intended for emulation.
track_contents = file_.read(6646);
file_.seek(2, SEEK_CUR);
number_of_bits = std::min(file_.get16le(), uint16_t(6646*8));
number_of_bits = std::min(file_.get_le<uint16_t>(), uint16_t(6646*8));
break;
default:
case Type::WOZ2: {
// In WOZ 2 an extra level of indirection allows for variable track sizes.
const uint16_t starting_block = file_.get16le();
const uint16_t starting_block = file_.get_le<uint16_t>();
file_.seek(2, SEEK_CUR); // Skip the block count; the amount of data to read is implied by the number of bits.
number_of_bits = file_.get32le();
number_of_bits = file_.get_le<uint32_t>();
file_.seek(starting_block * 512, SEEK_SET);
track_contents = file_.read((number_of_bits + 7) >> 3);

View File

@ -41,68 +41,10 @@ FileHolder::FileHolder(const std::string &file_name, FileMode ideal_mode)
if(!file_) throw Error::CantOpen;
}
uint32_t FileHolder::get32le() {
uint32_t result = uint32_t(std::fgetc(file_));
result |= uint32_t(std::fgetc(file_)) << 8;
result |= uint32_t(std::fgetc(file_)) << 16;
result |= uint32_t(std::fgetc(file_)) << 24;
return result;
}
uint32_t FileHolder::get32be() {
uint32_t result = uint32_t(std::fgetc(file_)) << 24;
result |= uint32_t(std::fgetc(file_)) << 16;
result |= uint32_t(std::fgetc(file_)) << 8;
result |= uint32_t(std::fgetc(file_));
return result;
}
uint32_t FileHolder::get24le() {
uint32_t result = uint32_t(std::fgetc(file_));
result |= uint32_t(std::fgetc(file_)) << 8;
result |= uint32_t(std::fgetc(file_)) << 16;
return result;
}
uint32_t FileHolder::get24be() {
uint32_t result = uint32_t(std::fgetc(file_)) << 16;
result |= uint32_t(std::fgetc(file_)) << 8;
result |= uint32_t(std::fgetc(file_));
return result;
}
uint16_t FileHolder::get16le() {
uint16_t result = uint16_t(std::fgetc(file_));
result |= uint16_t(uint16_t(std::fgetc(file_)) << 8);
return result;
}
uint16_t FileHolder::get16be() {
uint16_t result = uint16_t(uint16_t(std::fgetc(file_)) << 8);
result |= uint16_t(std::fgetc(file_));
return result;
}
uint8_t FileHolder::get8() {
return uint8_t(std::fgetc(file_));
}
void FileHolder::put16be(uint16_t value) {
std::fputc(value >> 8, file_);
std::fputc(value, file_);
}
void FileHolder::put16le(uint16_t value) {
std::fputc(value, file_);
std::fputc(value >> 8, file_);
}
void FileHolder::put8(uint8_t value) {
std::fputc(value, file_);
}

View File

@ -46,19 +46,13 @@ public:
*/
FileHolder(const std::string &file_name, FileMode ideal_mode = FileMode::ReadWrite);
/*!
Performs @c get8 four times on @c file, casting each result to a @c uint32_t
and returning the four assembled in little endian order.
*/
uint32_t get32le();
/*!
Writes @c value using successive @c put8s, in little endian order.
*/
template <typename T> void put_le(T value) {
auto bytes = sizeof(T);
while(bytes--) {
put8(value&0xff);
template <typename IntT, size_t bytes = 0>
void put_le(IntT value) {
for(size_t c = 0; c < bytes ? bytes : sizeof(IntT); c++) {
put8(uint8_t(value));
value >>= 8;
}
}
@ -66,8 +60,9 @@ public:
/*!
Writes @c value using successive @c put8s, in big endian order.
*/
template <typename T> void put_be(T value) {
auto shift = sizeof(T) * 8;
template <typename IntT, size_t bytes = 0>
void put_be(IntT value) {
auto shift = (bytes ? bytes : sizeof(IntT)) * 8;
while(shift) {
shift -= 8;
put8((value >> shift)&0xff);
@ -75,44 +70,32 @@ public:
}
/*!
Performs @c get8 four times on @c file, casting each result to a @c uint32_t
and returning the four assembled in big endian order.
Writes @c value using successive @c put8s, in little endian order.
*/
uint32_t get32be();
template <typename IntT, size_t bytes = 0>
IntT get_le() {
constexpr auto length = bytes ? bytes : sizeof(IntT);
IntT result{};
for(size_t c = 0; c < length; c++) {
result >>= 8;
result |= IntT(get8() << ((length - 1) * 8));
}
return result;
}
/*!
Performs @c get8 three times on @c file, casting each result to a @c uint32_t
and returning the three assembled in little endian order.
Writes @c value using successive @c put8s, in big endian order.
*/
uint32_t get24le();
/*!
Performs @c get8 three times on @c file, casting each result to a @c uint32_t
and returning the three assembled in big endian order.
*/
uint32_t get24be();
/*!
Performs @c get8 two times on @c file, casting each result to a @c uint32_t
and returning the two assembled in little endian order.
*/
uint16_t get16le();
/*!
Writes @c value using two successive @c put8s, in little endian order.
*/
void put16le(uint16_t value);
/*!
Performs @c get8 two times on @c file, casting each result to a @c uint32_t
and returning the two assembled in big endian order.
*/
uint16_t get16be();
/*!
Writes @c value using two successive @c put8s, in big endian order.
*/
void put16be(uint16_t value);
template <typename IntT, size_t bytes = 0>
IntT get_be() {
constexpr auto length = bytes ? bytes : sizeof(IntT);
IntT result{};
for(size_t c = 0; c < length; c++) {
result <<= 8;
result |= get8();
}
return result;
}
/*! Reads a single byte from @c file. */
uint8_t get8();

View File

@ -37,17 +37,17 @@ std::unique_ptr<Analyser::Static::Target> SNA::load(const std::string &file_name
const uint8_t i = file.get8();
// 01 HL'; 03 DE'; 05 BC'; 07 AF'
state->z80.registers.hl_dash = file.get16le();
state->z80.registers.de_dash = file.get16le();
state->z80.registers.bc_dash = file.get16le();
state->z80.registers.af_dash = file.get16le();
state->z80.registers.hl_dash = file.get_le<uint16_t>();
state->z80.registers.de_dash = file.get_le<uint16_t>();
state->z80.registers.bc_dash = file.get_le<uint16_t>();
state->z80.registers.af_dash = file.get_le<uint16_t>();
// 09 HL; 0B DE; 0D BC; 0F IY; 11 IX
state->z80.registers.hl = file.get16le();
state->z80.registers.de = file.get16le();
state->z80.registers.bc = file.get16le();
state->z80.registers.iy = file.get16le();
state->z80.registers.ix = file.get16le();
state->z80.registers.hl = file.get_le<uint16_t>();
state->z80.registers.de = file.get_le<uint16_t>();
state->z80.registers.bc = file.get_le<uint16_t>();
state->z80.registers.iy = file.get_le<uint16_t>();
state->z80.registers.ix = file.get_le<uint16_t>();
// 13 IFF2 (in bit 2)
const uint8_t iff = file.get8();
@ -60,7 +60,7 @@ std::unique_ptr<Analyser::Static::Target> SNA::load(const std::string &file_name
// 15 AF; 17 SP; 19 interrupt mode
state->z80.registers.flags = file.get8();
state->z80.registers.a = file.get8();
state->z80.registers.stack_pointer = file.get16le();
state->z80.registers.stack_pointer = file.get_le<uint16_t>();
state->z80.registers.interrupt_mode = file.get8();
// 1A border colour

View File

@ -73,8 +73,8 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
// Now parse all included blocks.
while(true) {
const uint32_t blockID = file.get32le();
const uint32_t size = file.get32le();
const uint32_t blockID = file.get_le<uint32_t>();
const uint32_t size = file.get_le<uint32_t>();
if(file.eof()) break;
const auto location = file.tell();
@ -88,19 +88,19 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
state->z80.registers.flags = file.get8();
state->z80.registers.a = file.get8();
state->z80.registers.bc = file.get16le();
state->z80.registers.de = file.get16le();
state->z80.registers.hl = file.get16le();
state->z80.registers.bc = file.get_le<uint16_t>();
state->z80.registers.de = file.get_le<uint16_t>();
state->z80.registers.hl = file.get_le<uint16_t>();
state->z80.registers.af_dash = file.get16le();
state->z80.registers.bc_dash = file.get16le();
state->z80.registers.de_dash = file.get16le();
state->z80.registers.hl_dash = file.get16le();
state->z80.registers.af_dash = file.get_le<uint16_t>();
state->z80.registers.bc_dash = file.get_le<uint16_t>();
state->z80.registers.de_dash = file.get_le<uint16_t>();
state->z80.registers.hl_dash = file.get_le<uint16_t>();
state->z80.registers.ix = file.get16le();
state->z80.registers.iy = file.get16le();
state->z80.registers.stack_pointer = file.get16le();
state->z80.registers.program_counter = file.get16le();
state->z80.registers.ix = file.get_le<uint16_t>();
state->z80.registers.iy = file.get_le<uint16_t>();
state->z80.registers.stack_pointer = file.get_le<uint16_t>();
state->z80.registers.program_counter = file.get_le<uint16_t>();
const uint8_t i = file.get8();
const uint8_t r = file.get8();
@ -110,7 +110,7 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
state->z80.registers.iff2 = file.get8();
state->z80.registers.interrupt_mode = file.get8();
state->video.half_cycles_since_interrupt = int(file.get32le()) * 2;
state->video.half_cycles_since_interrupt = int(file.get_le<uint32_t>()) * 2;
// SZX includes a count of remaining cycles that interrupt should be asserted for
// because it supports hardware that might cause an interrupt other than the display.
@ -124,7 +124,7 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
// verdict but I'm unclear what the effect of an invalid DD or FD is so
// have not yet implemented this.
state->z80.registers.memptr = file.get16le();
state->z80.registers.memptr = file.get_le<uint16_t>();
} break;
// ZXSTAYBLOCK
@ -139,7 +139,7 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
// ZXSTRAMPAGE
case block("RAMP"): {
const uint16_t flags = file.get16le();
const uint16_t flags = file.get_le<uint16_t>();
const uint8_t page = file.get8();
std::vector<uint8_t> contents;

View File

@ -71,11 +71,11 @@ std::unique_ptr<Analyser::Static::Target> Z80::load(const std::string &file_name
// Read version 1 header.
state->z80.registers.a = file.get8();
state->z80.registers.flags = file.get8();
state->z80.registers.bc = file.get16le();
state->z80.registers.hl = file.get16le();
state->z80.registers.program_counter = file.get16le();
state->z80.registers.stack_pointer = file.get16le();
state->z80.registers.ir = file.get16be(); // Stored I then R.
state->z80.registers.bc = file.get_le<uint16_t>();
state->z80.registers.hl = file.get_le<uint16_t>();
state->z80.registers.program_counter = file.get_le<uint16_t>();
state->z80.registers.stack_pointer = file.get_le<uint16_t>();
state->z80.registers.ir = file.get_be<uint16_t>(); // Stored I then R.
// Bit 7 of R is stored separately; likely this relates to an
// optimisation in the Z80 emulator that for some reason was
@ -84,13 +84,13 @@ std::unique_ptr<Analyser::Static::Target> Z80::load(const std::string &file_name
const uint8_t misc = (raw_misc == 0xff) ? 1 : raw_misc;
state->z80.registers.ir = uint16_t((state->z80.registers.ir & ~0x80) | ((misc&1) << 7));
state->z80.registers.de = file.get16le();
state->z80.registers.bc_dash = file.get16le();
state->z80.registers.de_dash = file.get16le();
state->z80.registers.hl_dash = file.get16le();
state->z80.registers.af_dash = file.get16be(); // Stored A' then F'.
state->z80.registers.iy = file.get16le();
state->z80.registers.ix = file.get16le();
state->z80.registers.de = file.get_le<uint16_t>();
state->z80.registers.bc_dash = file.get_le<uint16_t>();
state->z80.registers.de_dash = file.get_le<uint16_t>();
state->z80.registers.hl_dash = file.get_le<uint16_t>();
state->z80.registers.af_dash = file.get_be<uint16_t>(); // Stored A' then F'.
state->z80.registers.iy = file.get_le<uint16_t>();
state->z80.registers.ix = file.get_le<uint16_t>();
state->z80.registers.iff1 = bool(file.get8());
state->z80.registers.iff2 = bool(file.get8());
@ -111,12 +111,12 @@ std::unique_ptr<Analyser::Static::Target> Z80::load(const std::string &file_name
}
// This was a version 1 or 2 snapshot, so keep going...
const uint16_t bonus_header_size = file.get16le();
const uint16_t bonus_header_size = file.get_le<uint16_t>();
if(bonus_header_size != 23 && bonus_header_size != 54 && bonus_header_size != 55) {
return nullptr;
}
state->z80.registers.program_counter = file.get16le();
state->z80.registers.program_counter = file.get_le<uint16_t>();
const uint8_t model = file.get8();
switch(model) {
default: return nullptr;
@ -146,7 +146,7 @@ std::unique_ptr<Analyser::Static::Target> Z80::load(const std::string &file_name
if(bonus_header_size != 23) {
// More Z80, the emulator, lack of encapsulation to deal with here.
const uint16_t low_t_state = file.get16le();
const uint16_t low_t_state = file.get_le<uint16_t>();
const uint16_t high_t_state = file.get8();
switch(result->model) {
case Target::Model::SixteenK:
@ -181,7 +181,7 @@ std::unique_ptr<Analyser::Static::Target> Z80::load(const std::string &file_name
}
while(true) {
const uint16_t block_size = file.get16le();
const uint16_t block_size = file.get_le<uint16_t>();
const uint8_t page = file.get8();
const auto location = file.tell();
if(file.eof()) break;

View File

@ -114,7 +114,7 @@ CAS::CAS(const std::string &file_name) {
} else {
// Raw data appears now. Grab its length and keep going.
file.seek(header_position + 8, SEEK_SET);
const uint16_t length = file.get16le();
const uint16_t length = file.get_le<uint16_t>();
file.seek(header_position + 8, SEEK_SET);
chunks_.emplace_back(false, false, file.read(size_t(length) + 2));
@ -136,8 +136,8 @@ CAS::CAS(const std::string &file_name) {
// Get the start and end addresses in order to figure out how much data
// is here.
file.seek(header_position + 8, SEEK_SET);
const uint16_t start_address = file.get16le();
const uint16_t end_address = file.get16le();
const uint16_t start_address = file.get_le<uint16_t>();
const uint16_t end_address = file.get_le<uint16_t>();
file.seek(header_position + 8, SEEK_SET);
const auto length = end_address - start_address + 1;
@ -152,7 +152,7 @@ CAS::CAS(const std::string &file_name) {
file.seek(header_position + 8, SEEK_SET);
uint16_t address = 0x8001; // the BASIC start address.
while(true) {
const uint16_t next_line_address = file.get16le();
const uint16_t next_line_address = file.get_le<uint16_t>();
if(!next_line_address || file.eof()) break;
file.seek(next_line_address - address - 2, SEEK_CUR);
address = next_line_address;

View File

@ -36,7 +36,7 @@ CSW::CSW(const std::string &file_name) {
// The header now diverges based on version.
CompressionType compression_type;
if(major_version == 1) {
pulse_.length.clock_rate = file.get16le();
pulse_.length.clock_rate = file.get_le<uint16_t>();
if(file.get8() != 1) throw ErrorNotCSW;
compression_type = CompressionType::RLE;
@ -45,7 +45,7 @@ CSW::CSW(const std::string &file_name) {
file.seek(0x20, SEEK_SET);
} else {
pulse_.length.clock_rate = file.get32le();
pulse_.length.clock_rate = file.get_le<uint32_t>();
file.seek(4, SEEK_CUR); // Skip number of waves.
switch(file.get8()) {
case 1: compression_type = CompressionType::RLE; break;

View File

@ -89,7 +89,7 @@ Storage::Tape::Pulse CommodoreTAP::Serialiser::next_pulse() {
if(!updated_layout_ || next_byte > 0) {
next_length = uint32_t(next_byte) << 3;
} else {
next_length = file_.get24le();
next_length = file_.get_le<uint32_t, 3>();
}
if(file_.eof()) {

View File

@ -108,11 +108,11 @@ void TZX::Serialiser::push_next_pulses() {
}
void TZX::Serialiser::get_csw_recording_block() {
const uint32_t block_length = file_.get32le();
const uint16_t pause_after_block = file_.get16le();
const uint32_t sampling_rate = file_.get24le();
const uint8_t compression_type = file_.get8();
const uint32_t number_of_compressed_pulses = file_.get32le();
const auto block_length = file_.get_le<uint32_t>();
const auto pause_after_block = file_.get_le<uint16_t>();
const auto sampling_rate = file_.get_le<uint32_t, 3>();
const auto compression_type = file_.get8();
const auto number_of_compressed_pulses = file_.get_le<uint32_t>();
std::vector<uint8_t> raw_block = file_.read(block_length - 10);
@ -134,15 +134,15 @@ void TZX::Serialiser::get_csw_recording_block() {
}
void TZX::Serialiser::get_generalised_data_block() {
const uint32_t block_length = file_.get32le();
const uint32_t block_length = file_.get_le<uint32_t>();
const long endpoint = file_.tell() + long(block_length);
const uint16_t pause_after_block = file_.get16le();
const uint16_t pause_after_block = file_.get_le<uint16_t>();
const uint32_t total_pilot_symbols = file_.get32le();
const uint32_t total_pilot_symbols = file_.get_le<uint32_t>();
const uint8_t maximum_pulses_per_pilot_symbol = file_.get8();
const uint8_t symbols_in_pilot_table = file_.get8();
const uint32_t total_data_symbols = file_.get32le();
const uint32_t total_data_symbols = file_.get_le<uint32_t>();
const uint8_t maximum_pulses_per_data_symbol = file_.get8();
const uint8_t symbols_in_data_table = file_.get8();
@ -172,7 +172,7 @@ void TZX::Serialiser::get_generalised_segment(
Symbol symbol;
symbol.flags = file_.get8();
for(int ic = 0; ic < max_pulses_per_symbol; ic++) {
symbol.pulse_lengths.push_back(file_.get16le());
symbol.pulse_lengths.push_back(file_.get_le<uint16_t>());
}
symbol_table.push_back(symbol);
}
@ -193,7 +193,7 @@ void TZX::Serialiser::get_generalised_segment(
count = 1;
} else {
symbol_value = file_.get8();
count = file_.get16le();
count = file_.get_le<uint16_t>();
}
if(symbol_value > number_of_symbols) {
continue;
@ -227,8 +227,8 @@ void TZX::Serialiser::get_standard_speed_data_block() {
data_block.data.length_of_one_bit_pulse = 1710;
data_block.data.number_of_bits_in_final_byte = 8;
data_block.data.pause_after_block = file_.get16le();
data_block.data.data_length = file_.get16le();
data_block.data.pause_after_block = file_.get_le<uint16_t>();
data_block.data.data_length = file_.get_le<uint16_t>();
if(!data_block.data.data_length) return;
const uint8_t first_byte = file_.get8();
@ -240,15 +240,15 @@ void TZX::Serialiser::get_standard_speed_data_block() {
void TZX::Serialiser::get_turbo_speed_data_block() {
DataBlock data_block;
data_block.length_of_pilot_pulse = file_.get16le();
data_block.length_of_sync_first_pulse = file_.get16le();
data_block.length_of_sync_second_pulse = file_.get16le();
data_block.data.length_of_zero_bit_pulse = file_.get16le();
data_block.data.length_of_one_bit_pulse = file_.get16le();
data_block.length_of_pilot_tone = file_.get16le();
data_block.length_of_pilot_pulse = file_.get_le<uint16_t>();
data_block.length_of_sync_first_pulse = file_.get_le<uint16_t>();
data_block.length_of_sync_second_pulse = file_.get_le<uint16_t>();
data_block.data.length_of_zero_bit_pulse = file_.get_le<uint16_t>();
data_block.data.length_of_one_bit_pulse = file_.get_le<uint16_t>();
data_block.length_of_pilot_tone = file_.get_le<uint16_t>();
data_block.data.number_of_bits_in_final_byte = file_.get8();
data_block.data.pause_after_block = file_.get16le();
data_block.data.data_length = file_.get24le();
data_block.data.pause_after_block = file_.get_le<uint16_t>();
data_block.data.data_length = file_.get_le<uint32_t, 3>();
get_data_block(data_block);
}
@ -284,28 +284,28 @@ void TZX::Serialiser::get_data(const Data &data) {
}
void TZX::Serialiser::get_pure_tone_data_block() {
const uint16_t length_of_pulse = file_.get16le();
const uint16_t nunber_of_pulses = file_.get16le();
const uint16_t length_of_pulse = file_.get_le<uint16_t>();
const uint16_t nunber_of_pulses = file_.get_le<uint16_t>();
post_pulses(nunber_of_pulses, length_of_pulse);
}
void TZX::Serialiser::get_pure_data_block() {
Data data;
data.length_of_zero_bit_pulse = file_.get16le();
data.length_of_one_bit_pulse = file_.get16le();
data.length_of_zero_bit_pulse = file_.get_le<uint16_t>();
data.length_of_one_bit_pulse = file_.get_le<uint16_t>();
data.number_of_bits_in_final_byte = file_.get8();
data.pause_after_block = file_.get16le();
data.data_length = file_.get24le();
data.pause_after_block = file_.get_le<uint16_t>();
data.data_length = file_.get_le<uint32_t, 3>();
get_data(data);
}
void TZX::Serialiser::get_direct_recording_block() {
const Storage::Time length_per_sample(unsigned(file_.get16le()), StandardTZXClock);
const uint16_t pause_after_block = file_.get16le();
const Storage::Time length_per_sample(unsigned(file_.get_le<uint16_t>()), StandardTZXClock);
const auto pause_after_block = file_.get_le<uint16_t>();
uint8_t used_bits_in_final_byte = file_.get8();
const uint32_t length_of_data = file_.get24le();
const auto length_of_data = file_.get_le<uint32_t, 3>();
if(used_bits_in_final_byte < 1) used_bits_in_final_byte = 1;
if(used_bits_in_final_byte > 8) used_bits_in_final_byte = 8;
@ -334,12 +334,12 @@ void TZX::Serialiser::get_direct_recording_block() {
void TZX::Serialiser::get_pulse_sequence() {
uint8_t number_of_pulses = file_.get8();
while(number_of_pulses--) {
post_pulse(file_.get16le());
post_pulse(file_.get_le<uint16_t>());
}
}
void TZX::Serialiser::get_pause() {
const uint16_t duration = file_.get16le();
const uint16_t duration = file_.get_le<uint16_t>();
if(!duration) {
// TODO (maybe): post a 'pause the tape' suggestion
} else {
@ -354,14 +354,14 @@ void TZX::Serialiser::get_set_signal_level() {
}
void TZX::Serialiser::get_kansas_city_block() {
uint32_t block_length = file_.get32le();
uint32_t block_length = file_.get_le<uint32_t>();
const uint16_t pause_after_block = file_.get16le();
const uint16_t pilot_pulse_duration = file_.get16le();
const uint16_t pilot_length = file_.get16le();
const uint16_t pause_after_block = file_.get_le<uint16_t>();
const uint16_t pilot_pulse_duration = file_.get_le<uint16_t>();
const uint16_t pilot_length = file_.get_le<uint16_t>();
uint16_t pulse_durations[2];
pulse_durations[0] = file_.get16le();
pulse_durations[1] = file_.get16le();
pulse_durations[0] = file_.get_le<uint16_t>();
pulse_durations[1] = file_.get_le<uint16_t>();
const uint8_t packed_pulse_counts = file_.get8();
const unsigned int pulse_counts[2] = {
unsigned((((packed_pulse_counts >> 4) - 1) & 15) + 1),
@ -445,12 +445,12 @@ void TZX::Serialiser::ignore_group_end() {
}
void TZX::Serialiser::ignore_jump_to_block() {
const uint16_t target = file_.get16le();
const uint16_t target = file_.get_le<uint16_t>();
(void)target;
}
void TZX::Serialiser::ignore_loop_start() {
const uint16_t number_of_repetitions = file_.get16le();
const uint16_t number_of_repetitions = file_.get_le<uint16_t>();
(void)number_of_repetitions;
}
@ -458,7 +458,7 @@ void TZX::Serialiser::ignore_loop_end() {
}
void TZX::Serialiser::ignore_call_sequence() {
const uint16_t number_of_entries = file_.get16le();
const uint16_t number_of_entries = file_.get_le<uint16_t>();
file_.seek(number_of_entries * sizeof(uint16_t), SEEK_CUR);
}
@ -466,7 +466,7 @@ void TZX::Serialiser::ignore_return_from_sequence() {
}
void TZX::Serialiser::ignore_select_block() {
const uint16_t length_of_block = file_.get16le();
const uint16_t length_of_block = file_.get_le<uint16_t>();
file_.seek(length_of_block, SEEK_CUR);
}
@ -476,7 +476,7 @@ void TZX::Serialiser::ignore_stop_tape_if_in_48kb_mode() {
void TZX::Serialiser::ignore_custom_info_block() {
file_.seek(0x10, SEEK_CUR);
const uint32_t length = file_.get32le();
const uint32_t length = file_.get_le<uint32_t>();
file_.seek(length, SEEK_CUR);
}
@ -495,7 +495,7 @@ void TZX::Serialiser::ignore_message_block() {
}
void TZX::Serialiser::ignore_archive_info() {
const uint16_t length = file_.get16le();
const uint16_t length = file_.get_le<uint16_t>();
file_.seek(length, SEEK_CUR);
}

View File

@ -56,7 +56,7 @@ PRG::PRG(const std::string &file_name) : file_name_(file_name) {
if(file.stats().st_size >= 65538 || file.stats().st_size < 3)
throw ErrorBadFormat;
load_address_ = file.get16le();
load_address_ = file.get_le<uint16_t>();
length_ = uint16_t(file.stats().st_size - 2);
if(load_address_ + length_ >= 65536)

View File

@ -27,7 +27,7 @@ ZXSpectrumTAP::ZXSpectrumTAP(const std::string &file_name) : file_name_(file_nam
// To consider: could also check those blocks of type 0
// and type ff for valid checksums?
while(file.tell() != file.stats().st_size) {
const uint16_t block_length = file.get16le();
const uint16_t block_length = file.get_le<uint16_t>();
if(file.eof() || file.tell() + block_length > file.stats().st_size) {
throw ErrorNotZXSpectrumTAP;
}
@ -121,7 +121,7 @@ void ZXSpectrumTAP::Serialiser::read_next_block() {
if(file_.tell() == file_.stats().st_size) {
phase_ = Phase::Gap;
} else {
block_length_ = file_.get16le();
block_length_ = file_.get_le<uint16_t>();
data_byte_ = block_type_ = file_.get8();
phase_ = Phase::PilotTone;
}