diff --git a/Storage/Disk/DiskImage/Formats/AmigaADF.cpp b/Storage/Disk/DiskImage/Formats/AmigaADF.cpp index 47a1c999d..883794bc2 100644 --- a/Storage/Disk/DiskImage/Formats/AmigaADF.cpp +++ b/Storage/Disk/DiskImage/Formats/AmigaADF.cpp @@ -18,6 +18,11 @@ using namespace Storage::Disk; namespace { +/// Builds a buffer containing the bytes between @c begin and @c end split up so that the nibbles in the first half of the buffer +/// consist of the odd bits of the source bytes — b1, b3, b5 and b7 — ordered so that most-significant nibbles come before +/// least-significant ones, and the second half of the buffer contains the even bits. +/// +/// Nibbles are written to @c first; it is assumed that an even number of source bytes have been supplied. template void encode_block(IteratorT begin, IteratorT end, OutputIt first) { // Parse 1: combine odd bits. auto cursor = begin; @@ -62,13 +67,9 @@ template void encode_block(IteratorT begin, } } -template void write(IteratorT begin, IteratorT end, std::unique_ptr &encoder) { - while(begin != end) { - encoder->add_byte(*begin); - ++begin; - } -} - +/// Construsts the Amiga-style checksum of the bytes between @c begin and @c end, which is a 32-bit exclusive OR of the source data +/// with each byte converted into a 16-bit word by inserting a 0 bit between every data bit, and then combined into 32-bit words in +/// big endian order. template auto checksum(IteratorT begin, IteratorT end) { uint16_t checksum[2]{}; int offset = 0; @@ -99,6 +100,8 @@ template auto checksum(IteratorT begin, IteratorT end) { }; } +/// Obtains the Amiga-style checksum of the data between @c begin and @c end, then odd-even encodes it and writes +/// it out to @c encoder. template void write_checksum(IteratorT begin, IteratorT end, std::unique_ptr &encoder) { // Believe it or not, this appears to be the actual checksum algorithm on the Amiga: // @@ -110,7 +113,7 @@ template void write_checksum(IteratorT begin, IteratorT end std::decay_t encoded_checksum{}; encode_block(raw_checksum.begin(), raw_checksum.end(), encoded_checksum.begin()); - write(encoded_checksum.begin(), encoded_checksum.end(), encoder); + encoder->add_bytes(encoded_checksum.begin(), encoded_checksum.end()); } } @@ -164,11 +167,11 @@ std::shared_ptr AmigaADF::get_track_at_position(Track::Address address) { }; std::array encoded_header; encode_block(std::begin(header), std::end(header), std::begin(encoded_header)); - write(std::begin(encoded_header), std::end(encoded_header), encoder); + encoder->add_bytes(std::begin(encoded_header), std::end(encoded_header)); // Write the sector label. const std::array os_recovery{}; - write(os_recovery.begin(), os_recovery.end(), encoder); + encoder->add_bytes(os_recovery.begin(), os_recovery.end()); // Encode the data. std::array encoded_data; @@ -179,7 +182,7 @@ std::shared_ptr AmigaADF::get_track_at_position(Track::Address address) { write_checksum(std::begin(encoded_data), std::end(encoded_data), encoder); // Write data. - write(std::begin(encoded_data), std::end(encoded_data), encoder); + encoder->add_bytes(std::begin(encoded_data), std::end(encoded_data)); } return std::make_shared(std::move(encoded_segment)); diff --git a/Storage/Disk/Encodings/MFM/Encoder.hpp b/Storage/Disk/Encodings/MFM/Encoder.hpp index 8c5c5fc09..71a48661b 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.hpp +++ b/Storage/Disk/Encodings/MFM/Encoder.hpp @@ -55,6 +55,17 @@ class Encoder { virtual void add_deleted_data_address_mark() = 0; virtual void output_short(uint16_t value, uint16_t fuzzy_mask = 0); + template void add_bytes(IteratorT begin, IteratorT end) { + while(begin != end) { + add_byte(*begin); + ++begin; + } + } + + template void add_bytes(const ContainerT &container) { + write(std::begin(container), std::end(container)); + } + /// Outputs the CRC for all data since the last address mask; if @c incorrectly is @c true then outputs an incorrect CRC. void add_crc(bool incorrectly);