diff options
Diffstat (limited to 'src/lib/formats/hti_tape.cpp')
-rw-r--r-- | src/lib/formats/hti_tape.cpp | 192 |
1 files changed, 104 insertions, 88 deletions
diff --git a/src/lib/formats/hti_tape.cpp b/src/lib/formats/hti_tape.cpp index 29bab6cd51c..7d6119860f1 100644 --- a/src/lib/formats/hti_tape.cpp +++ b/src/lib/formats/hti_tape.cpp @@ -8,11 +8,15 @@ #include "hti_tape.h" -#include "imageutl.h" +#include "ioprocs.h" +#include "multibyte.h" + +#include <tuple> static constexpr uint32_t OLD_FILE_MAGIC = 0x5441434f; // Magic value at start of old-format image file: "TACO" -static constexpr uint32_t FILE_MAGIC = 0x48544930; // Magic value at start of image file: "HTI0" +static constexpr uint32_t FILE_MAGIC_DELTA = 0x48544930; // Magic value at start of delta-modulation image file: "HTI0" +static constexpr uint32_t FILE_MAGIC_MANCHESTER = 0x48544931; // Magic value at start of manchester-modulation image file: "HTI1" // *** Position of tape holes *** // At beginning of tape: @@ -41,25 +45,32 @@ static const hti_format_t::tape_pos_t tape_holes[] = { }; hti_format_t::hti_format_t() - : m_bits_per_word(16) + : m_img_format(HTI_DELTA_MOD_16_BITS) { clear_tape(); } -bool hti_format_t::load_tape(io_generic *io) +bool hti_format_t::load_tape(util::random_read &io) { - uint8_t tmp[ 4 ]; + if (io.seek(0, SEEK_SET)) { + return false; + } - io_generic_read(io, tmp, 0, 4); - auto magic = pick_integer_be(tmp , 0 , 4); - if (magic != FILE_MAGIC && magic != OLD_FILE_MAGIC) { + uint8_t tmp[4]; + auto const [err, actual] = read(io, tmp, 4); + if (err || (4 != actual)) { return false; } - uint64_t offset = 4; + auto magic = get_u32be(tmp); + if (((m_img_format == HTI_DELTA_MOD_16_BITS || m_img_format == HTI_DELTA_MOD_17_BITS) && magic != FILE_MAGIC_DELTA && magic != OLD_FILE_MAGIC) || + (m_img_format == HTI_MANCHESTER_MOD && magic != FILE_MAGIC_MANCHESTER)) { + return false; + } - for (tape_track_t& track : m_tracks) { - if (!load_track(io , offset , track , magic == OLD_FILE_MAGIC)) { + for (unsigned i = 0; i < no_of_tracks(); i++) { + tape_track_t &track = m_tracks[i]; + if (!load_track(io, track, magic == OLD_FILE_MAGIC)) { clear_tape(); return false; } @@ -68,46 +79,46 @@ bool hti_format_t::load_tape(io_generic *io) return true; } -void hti_format_t::save_tape(io_generic *io) +void hti_format_t::save_tape(util::random_read_write &io) { - uint8_t tmp[ 4 ]; + io.seek(0, SEEK_SET); // FIXME: check for errors - place_integer_be(tmp, 0, 4, FILE_MAGIC); - io_generic_write(io, tmp, 0, 4); + uint8_t tmp[4]; - uint64_t offset = 4; + put_u32be(tmp, m_img_format == HTI_MANCHESTER_MOD ? FILE_MAGIC_MANCHESTER : FILE_MAGIC_DELTA); + write(io, tmp, 4); // FIXME: check for errors - for (const tape_track_t& track : m_tracks) { - tape_pos_t next_pos = (tape_pos_t)-1; + for (unsigned i = 0; i < no_of_tracks(); i++) { + const tape_track_t &track = m_tracks[i]; + tape_pos_t next_pos = tape_pos_t(-1); unsigned n_words = 0; tape_track_t::const_iterator it_start; for (tape_track_t::const_iterator it = track.cbegin(); it != track.cend(); ++it) { if (it->first != next_pos) { - dump_sequence(io , offset , it_start , n_words); + dump_sequence(io, it_start, n_words); it_start = it; n_words = 0; } next_pos = it->first + word_length(it->second); n_words++; } - dump_sequence(io , offset , it_start , n_words); + dump_sequence(io, it_start, n_words); // End of track - place_integer_le(tmp, 0, 4, (uint32_t)-1); - io_generic_write(io, tmp, offset, 4); - offset += 4; + put_u32le(tmp, (uint32_t)-1); + write(io, tmp, 4); // FIXME: check for errors } } void hti_format_t::clear_tape() { - for (tape_track_t& track : m_tracks) { + for (tape_track_t &track : m_tracks) { track.clear(); } } -hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) +hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) const { - unsigned zeros , ones; + unsigned zeros, ones; // pop count of w ones = (w & 0x5555) + ((w >> 1) & 0x5555); @@ -117,10 +128,10 @@ hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) zeros = 16 - ones; - return zeros * ZERO_BIT_LEN + ones * ONE_BIT_LEN; + return zeros * bit_length(false) + ones * bit_length(true); } -hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , bool forward) +hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t &it, bool forward) const { if (forward) { return word_end_pos(it); @@ -129,7 +140,7 @@ hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , } } -bool hti_format_t::pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset) +bool hti_format_t::pos_offset(tape_pos_t &pos, bool forward, tape_pos_t offset) { if (offset == 0) { return true; @@ -153,7 +164,7 @@ bool hti_format_t::pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset } } -hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) +hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos, bool forward) { if (forward) { for (tape_pos_t hole : tape_holes) { @@ -164,9 +175,9 @@ hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) // No more holes: will hit end of tape return NULL_TAPE_POS; } else { - for (int i = (sizeof(tape_holes) / sizeof(tape_holes[ 0 ])) - 1; i >= 0; i--) { - if (tape_holes[ i ] < pos) { - return tape_holes[ i ]; + for (int i = (sizeof(tape_holes) / sizeof(tape_holes[0])) - 1; i >= 0; i--) { + if (tape_holes[i] < pos) { + return tape_holes[i]; } } // No more holes: will hit start of tape @@ -174,45 +185,45 @@ hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) } } -void hti_format_t::write_word(unsigned track_no , tape_pos_t start , tape_word_t word , tape_pos_t& length , bool forward) +void hti_format_t::write_word(unsigned track_no, tape_pos_t start, tape_word_t word, tape_pos_t &length, bool forward) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(start); - adjust_it(track , it_low , start); + adjust_it(track, it_low, start); length = word_length(word); tape_pos_t end_pos = start + length; track_iterator_t it_high = track.lower_bound(end_pos); - track.erase(it_low , it_high); + track.erase(it_low, it_high); // A 0 word is inserted after the word being written, if space allows. // This is meant to avoid fragmentation of the slack space at the end of a record // as the record expands & contracts when re-written with different content. // Without this fix, a gap could form in the slack big enough to cause // false gap detections. - if (forward && it_high != track.end() && (it_high->first - end_pos) >= (ZERO_BIT_LEN * 16)) { + if (forward && it_high != track.end() && (it_high->first - end_pos) >= (bit_length(false) * 16)) { track.insert(it_high, std::make_pair(end_pos, 0)); it_high--; } - track.insert(it_high , std::make_pair(start, word)); + track.insert(it_high, std::make_pair(start, word)); } -void hti_format_t::write_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) +void hti_format_t::write_gap(unsigned track_no, tape_pos_t a, tape_pos_t b) { - ensure_a_lt_b(a , b); - tape_track_t& track = m_tracks[ track_no ]; + ensure_a_lt_b(a, b); + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(a); - adjust_it(track , it_low , a); + adjust_it(track, it_low, a); track_iterator_t it_high = track.lower_bound(b); track.erase(it_low, it_high); } -bool hti_format_t::just_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) +bool hti_format_t::just_gap(unsigned track_no, tape_pos_t a, tape_pos_t b) { - ensure_a_lt_b(a , b); - tape_track_t& track = m_tracks[ track_no ]; + ensure_a_lt_b(a, b); + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(a); track_iterator_t it_high = track.lower_bound(b); @@ -221,9 +232,9 @@ bool hti_format_t::just_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) return it_low == it_high; } -bool hti_format_t::next_data(unsigned track_no , tape_pos_t pos , bool forward , bool inclusive , track_iterator_t& it) +bool hti_format_t::next_data(unsigned track_no, tape_pos_t pos, bool forward, bool inclusive, track_iterator_t &it) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; it = track.lower_bound(pos); if (forward) { if (inclusive) { @@ -243,9 +254,9 @@ bool hti_format_t::next_data(unsigned track_no , tape_pos_t pos , bool forward , } } -hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no , bool forward , track_iterator_t& it) +hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no, bool forward, track_iterator_t &it) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; if (forward) { tape_pos_t prev_pos = word_end_pos(it); ++it; @@ -267,7 +278,7 @@ hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no , bool forward , } } -bool hti_format_t::sync_with_record(unsigned track_no , track_iterator_t& it , unsigned& bit_idx) +bool hti_format_t::sync_with_record(unsigned track_no, track_iterator_t &it, unsigned &bit_idx) { while ((it->second & (1U << bit_idx)) == 0) { if (bit_idx) { @@ -288,7 +299,7 @@ bool hti_format_t::sync_with_record(unsigned track_no , track_iterator_t& it , u return true; } -hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no , track_iterator_t& it , unsigned& bit_idx , tape_word_t& word) +hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no, track_iterator_t &it, unsigned &bit_idx, tape_word_t &word) { if (bit_idx == 15) { auto res = adv_it(track_no, true, it); @@ -311,13 +322,13 @@ hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no , track_iterat } } -bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , tape_pos_t min_gap) +bool hti_format_t::next_gap(unsigned track_no, tape_pos_t &pos, bool forward, tape_pos_t min_gap) { tape_track_t::iterator it; // First align with next data - next_data(track_no , pos , forward , true , it); + next_data(track_no, pos, forward, true, it); // Then scan for 1st gap - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; bool done = false; track_iterator_t prev_it; unsigned n_gaps = 1; @@ -338,7 +349,7 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , adv_res_t adv_res; do { prev_it = it; - adv_res = adv_it(track_no , forward , it); + adv_res = adv_it(track_no, forward, it); } while (adv_res == ADV_CONT_DATA); pos = word_end_pos(prev_it); } @@ -358,33 +369,37 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , adv_res_t adv_res; do { prev_it = it; - adv_res = adv_it(track_no , forward , it); + adv_res = adv_it(track_no, forward, it); } while (adv_res == ADV_CONT_DATA); pos = prev_it->first; } } // Set "pos" where minimum gap size is met - pos_offset(pos , forward , min_gap); + pos_offset(pos, forward, min_gap); return n_gaps == 0; } -bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track , bool old_format) +bool hti_format_t::load_track(util::random_read &io, tape_track_t &track, bool old_format) { - uint8_t tmp[ 4 ]; - uint32_t tmp32; tape_pos_t delta_pos = 0; tape_pos_t last_word_end = 0; track.clear(); while (1) { - // Read no. of words to follow - io_generic_read(io, tmp, offset, 4); - offset += 4; + std::error_condition err; + size_t actual; + uint8_t tmp[4]; + uint32_t tmp32; - tmp32 = pick_integer_le(tmp, 0, 4); + // Read no. of words to follow + std::tie(err, actual) = read(io, tmp, 4); + if (err || (4 != actual)) { + return false; + } + tmp32 = get_u32le(tmp); // Track ends if (tmp32 == (uint32_t)-1) { @@ -394,10 +409,11 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& unsigned n_words = tmp32; // Read tape position of block - io_generic_read(io, tmp, offset, 4); - offset += 4; - - tmp32 = pick_integer_le(tmp, 0, 4); + std::tie(err, actual) = read(io, tmp, 4); + if (err || (4 != actual)) { + return false; + } + tmp32 = get_u32le(tmp); tape_pos_t pos = (tape_pos_t)tmp32 + delta_pos; @@ -407,14 +423,16 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& for (unsigned i = 0; i < n_words; i++) { uint16_t tmp16; - io_generic_read(io, tmp, offset, 2); - offset += 2; - tmp16 = pick_integer_le(tmp, 0, 2); + std::tie(err, actual) = read(io, tmp, 2); + if (err || (2 != actual)) { + return false; + } + tmp16 = get_u16le(tmp); if (!old_format) { - track.insert(std::make_pair(pos , tmp16)); + track.insert(std::make_pair(pos, tmp16)); pos += word_length(tmp16); - } else if (m_bits_per_word == 16) { + } else if (m_img_format == HTI_DELTA_MOD_16_BITS) { // Convert HP9845 & HP85 old format // Basically, in old format each word had 17 bits (an implicit 1 // was added at the end). In new format we just keep the 16 bits @@ -429,7 +447,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track.insert(std::make_pair(pos, tmp16)); pos += word_length(tmp16); last_word_end = pos; - delta_pos -= ONE_BIT_LEN; + delta_pos -= DELTA_ONE_BIT_LEN; } else { // Convert HP9825 old format // In moving from old to new format we make the 17th bit at the @@ -458,37 +476,35 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& } if (bits_in_accum) { track.insert(std::make_pair(pos, word_accum)); - tape_pos_t shift = (tape_pos_t)(16 - bits_in_accum) * ZERO_BIT_LEN; + tape_pos_t shift = (tape_pos_t)(16 - bits_in_accum) * DELTA_ZERO_BIT_LEN; delta_pos += shift; last_word_end = pos + word_length(word_accum); } } } -void hti_format_t::dump_sequence(io_generic *io , uint64_t& offset , tape_track_t::const_iterator it_start , unsigned n_words) +void hti_format_t::dump_sequence(util::random_read_write &io, tape_track_t::const_iterator it_start, unsigned n_words) { if (n_words) { - uint8_t tmp[ 8 ]; - place_integer_le(tmp, 0, 4, n_words); - place_integer_le(tmp, 4, 4, it_start->first); - io_generic_write(io, tmp, offset, 8); - offset += 8; + uint8_t tmp[8]; + put_u32le(&tmp[0], n_words); + put_u32le(&tmp[4], it_start->first); + write(io, tmp, 8); // FIXME: check for errors for (unsigned i = 0; i < n_words; i++) { - place_integer_le(tmp, 0, 2, it_start->second); - io_generic_write(io, tmp, offset, 2); - offset += 2; + put_u16le(tmp, it_start->second); + write(io, tmp, 2); // FIXME: check for errors ++it_start; } } } -hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t& it) +hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t &it) const { return it->first + word_length(it->second); } -void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) +void hti_format_t::adjust_it(tape_track_t &track, track_iterator_t &it, tape_pos_t pos) const { if (it != track.begin()) { --it; @@ -498,7 +514,7 @@ void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_p } } -void hti_format_t::ensure_a_lt_b(tape_pos_t& a , tape_pos_t& b) +void hti_format_t::ensure_a_lt_b(tape_pos_t &a, tape_pos_t &b) { if (a > b) { // Ensure A always comes before B |