1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Parses data and gap stream elements.

This commit is contained in:
Thomas Harte 2021-12-27 18:12:44 -05:00
parent 9d3cf9c73c
commit 9b6ccbcc95
2 changed files with 121 additions and 2 deletions

View File

@ -21,6 +21,15 @@ constexpr uint32_t block(const char (& src)[5]) {
); );
} }
constexpr size_t block_size(Storage::FileHolder &file, uint8_t header) {
uint8_t size_width = header >> 5;
size_t length = 0;
while(size_width--) {
length = (length << 8) | file.get8();
}
return length;
}
} }
@ -64,8 +73,11 @@ IPF::IPF(const std::string &file_name) : file_(file_name) {
throw Error::InvalidFormat; throw Error::InvalidFormat;
} }
// Skip: encoder type, revision, file key and revision, CRC of the original .ctr, and minimum track. // Determine whether this is a newer SPS-style file.
file_.seek(24, SEEK_CUR); is_sps_format_ = file_.get32be() > 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_.get32be());
// Skip: min side. // Skip: min side.
@ -173,5 +185,111 @@ int IPF::get_head_count() {
} }
std::shared_ptr<Track> IPF::get_track_at_position([[maybe_unused]] Track::Address address) { std::shared_ptr<Track> IPF::get_track_at_position([[maybe_unused]] Track::Address address) {
// Get the track description, if it exists, and check either that the file has contents for the track.
auto pair = tracks_.find(address);
if(pair == tracks_.end()) {
return nullptr;
}
const TrackDescription &description = pair->second;
if(!description.file_offset) {
return nullptr;
}
// Seek to track content.
file_.seek(description.file_offset, SEEK_SET);
// Read the block descriptions up front.
//
// This is less efficient than just seeking for each block in turn,
// but is a useful crutch to comprehension of the file format on a
// first run through.
struct BlockDescriptor {
uint32_t data_bits = 0;
uint32_t gap_bits = 0;
uint32_t gap_offset = 0;
bool is_mfm = false;
bool has_forward_gap = false;
bool has_backwards_gap = false;
bool data_unit_is_bits = false;
uint32_t default_gap_value = 0;
uint32_t data_offset = 0;
};
std::vector<BlockDescriptor> blocks;
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();
if(is_sps_format_) {
block.gap_offset = file_.get32be();
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;
const uint32_t flags = file_.get32be();
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();
}
// TODO: Append as necessary for each gap and data stream as per above.
for(auto &block: blocks) {
if(block.gap_offset) {
file_.seek(description.file_offset + block.gap_offset, SEEK_SET);
while(true) {
const uint8_t gap_header = file_.get8();
if(!gap_header) break;
// Decompose the header and read the length.
enum class Type {
None, GapLength, SampleLength
} type = Type(gap_header & 0x1f);
const size_t length = block_size(file_, gap_header);
// TODO: write the gap.
switch(type) {
case Type::GapLength:
printf("Unhandled gap length %zu\n", length);
break;
default:
case Type::SampleLength:
printf("Unhandled sampled gap length %zu\n", length);
file_.seek(long(length >> 3), SEEK_CUR);
break;
}
}
}
if(block.data_offset) {
file_.seek(description.file_offset + block.data_offset, SEEK_SET);
while(true) {
const uint8_t data_header = file_.get8();
if(!data_header) break;
// Decompose the header and read the length.
enum class Type {
None, Sync, Data, Gap, Raw, Fuzzy
} type = Type(data_header & 0x1f);
const size_t length = block_size(file_, data_header) * (block.data_unit_is_bits ? 1 : 8);
// TODO: write the data.
switch(type) {
default:
printf("Unhandled data type %d, length %zu\n", int(type), length);
file_.seek(long(length >> 3), SEEK_CUR);
break;
}
}
}
printf("\n");
}
return nullptr; return nullptr;
} }

View File

@ -68,6 +68,7 @@ class IPF: public DiskImage, public TargetPlatform::TypeDistinguisher {
int head_count_; int head_count_;
int track_count_; int track_count_;
std::map<Track::Address, TrackDescription> tracks_; std::map<Track::Address, TrackDescription> tracks_;
bool is_sps_format_ = false;
TargetPlatform::Type target_platform_type() final { TargetPlatform::Type target_platform_type() final {
return TargetPlatform::Type(platform_type_); return TargetPlatform::Type(platform_type_);