1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-17 13:29:02 +00:00
CLK/Storage/Disk/DiskImage/Formats/HFE.cpp

110 lines
3.0 KiB
C++
Raw Normal View History

//
// HFE.cpp
// Clock Signal
//
// Created by Thomas Harte on 17/08/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#include "HFE.hpp"
2017-09-23 02:39:23 +00:00
#include "../../Track/PCMTrack.hpp"
2017-10-04 01:24:20 +00:00
#include "../../Track/TrackSerialiser.hpp"
#include "../../../Data/BitReverse.hpp"
2017-08-18 02:20:02 +00:00
using namespace Storage::Disk;
HFE::HFE(const char *file_name) :
Storage::FileHolder(file_name) {
2017-08-18 02:20:02 +00:00
if(!check_signature("HXCPICFE", 8)) throw ErrorNotHFE;
if(fgetc(file_)) throw ErrorNotHFE;
track_count_ = fgetc(file_);
head_count_ = fgetc(file_);
2017-08-18 02:20:02 +00:00
fseek(file_, 7, SEEK_CUR);
track_list_offset_ = static_cast<long>(fgetc16le() << 9);
}
HFE::~HFE() {
}
int HFE::get_head_position_count() {
return track_count_;
}
int HFE::get_head_count() {
return head_count_;
}
/*!
Seeks to the beginning of the track at @c position underneath @c head,
returning its length in bytes.
To read the track, start from the current file position, read 256 bytes,
skip 256 bytes, read 256 bytes, skip 256 bytes, etc.
*/
uint16_t HFE::seek_track(Track::Address address) {
2017-08-18 02:20:02 +00:00
// Get track position and length from the lookup table; data is then always interleaved
// based on an assumption of two heads.
fseek(file_, track_list_offset_ + address.position * 4, SEEK_SET);
2017-08-18 02:20:02 +00:00
long track_offset = static_cast<long>(fgetc16le() << 9);
2017-08-18 02:20:02 +00:00
uint16_t track_length = fgetc16le();
fseek(file_, track_offset, SEEK_SET);
if(address.head) fseek(file_, 256, SEEK_CUR);
2017-08-18 02:20:02 +00:00
return track_length / 2;
}
std::shared_ptr<Track> HFE::get_track_at_position(Track::Address address) {
2017-08-18 02:20:02 +00:00
PCMSegment segment;
2017-10-04 01:24:20 +00:00
{
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
uint16_t track_length = seek_track(address);
2017-10-04 01:24:20 +00:00
segment.data.resize(track_length);
segment.number_of_bits = track_length * 8;
uint16_t c = 0;
while(c < track_length) {
uint16_t length = static_cast<uint16_t>(std::min(256, track_length - c));
2017-10-04 01:24:20 +00:00
fread(&segment.data[c], 1, length, file_);
c += length;
fseek(file_, 256, SEEK_CUR);
}
2017-08-18 02:20:02 +00:00
}
// Flip bytes; HFE's preference is that the least-significant bit
// is serialised first, but PCMTrack posts the most-significant first.
Storage::Data::BitReverse::reverse(segment.data);
2017-08-18 02:20:02 +00:00
std::shared_ptr<Track> track(new PCMTrack(segment));
return track;
}
void HFE::set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) {
for(auto &track : tracks) {
std::unique_lock<std::mutex> lock_guard(file_access_mutex_);
uint16_t track_length = seek_track(track.first);
lock_guard.unlock();
2017-10-04 01:24:20 +00:00
PCMSegment segment = Storage::Disk::track_serialisation(*track.second, Storage::Time(1, track_length * 8));
Storage::Data::BitReverse::reverse(segment.data);
uint16_t data_length = std::min(static_cast<uint16_t>(segment.data.size()), track_length);
2017-10-04 01:24:20 +00:00
lock_guard.lock();
seek_track(track.first);
2017-10-04 01:24:20 +00:00
uint16_t c = 0;
while(c < data_length) {
uint16_t length = static_cast<uint16_t>(std::min(256, data_length - c));
fwrite(&segment.data[c], 1, length, file_);
c += length;
fseek(file_, 256, SEEK_CUR);
}
lock_guard.unlock();
2017-10-04 01:24:20 +00:00
}
}