diff --git a/Storage/Disk/DiskImage/Formats/NIB.cpp b/Storage/Disk/DiskImage/Formats/NIB.cpp index 269f1a8fa..da6e883d1 100644 --- a/Storage/Disk/DiskImage/Formats/NIB.cpp +++ b/Storage/Disk/DiskImage/Formats/NIB.cpp @@ -75,7 +75,9 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di // Establish where syncs start by finding instances of 0xd5 0xaa and then regressing // from each along all preceding FFs. for(size_t index = 0; index < track_data.size(); ++index) { + // This is a D5 AA... if(track_data[index] == 0xd5 && track_data[(index+1)%track_data.size()] == 0xaa) { + // ... count backwards to find out where the preceding FFs started. size_t start = index - 1; size_t length = 0; while(track_data[start] == 0xff && length < 5) { @@ -83,8 +85,13 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di ++length; } + // Record a sync position only if there were at least five FFs. if(length == 5) { sync_starts.insert((start + 1) % track_data.size()); + + // If the apparent start of this sync area is 'after' the start, then + // this sync period overlaps position zero. So this track will start + // in a sync block. if(start > index) start_index = start; } @@ -92,25 +99,36 @@ std::shared_ptr<::Storage::Disk::Track> NIB::get_track_at_position(::Storage::Di } PCMSegment segment; + + // If the track started in a sync block, write sync first. if(start_index) { segment += Encodings::AppleGCR::six_and_two_sync(static_cast(start_index)); } std::size_t index = start_index; - for(const auto &location: sync_starts) { - // Write from index to sync_start. + for(const auto location: sync_starts) { + // Write data from index to sync_start. std::vector data_segment( track_data.begin() + static_cast(index), track_data.begin() + static_cast(location)); segment += PCMSegment(data_segment); - // Add a sync from sync_start to end of 0xffs. - if(location == track_length-1) break; - + // Add a sync from sync_start to end of 0xffs, if there are + // any before the end of data. index = location; while(index < track_length && track_data[index] == 0xff) ++index; - segment += Encodings::AppleGCR::six_and_two_sync(static_cast(index - location)); + + if(index - location) + segment += Encodings::AppleGCR::six_and_two_sync(static_cast(index - location)); + } + + // If there's still data remaining on the track, write it out. + if(index < track_length) { + std::vector data_segment( + track_data.begin() + static_cast(index), + track_data.end()); + segment += PCMSegment(data_segment); } return std::make_shared(segment); @@ -129,20 +147,29 @@ void NIB::set_tracks(const std::map> &tra std::vector track; track.reserve(track_length); uint8_t shifter = 0; + int bit_count = 0; + size_t sync_location = 0, location = 0; for(const auto bit: segment.data) { shifter = static_cast((shifter << 1) | (bit ? 1 : 0)); + ++bit_count; + ++location; if(shifter & 0x80) { track.push_back(shifter); + if(bit_count == 10) { + sync_location = location; + } shifter = 0; + bit_count = 0; } } - // Pad out to track_length. + // Trim or pad out to track_length. if(track.size() > track_length) { track.resize(track_length); } else { while(track.size() < track_length) { - track.push_back(0xff); + std::vector extra_data(static_cast(track_length) - track.size(), 0xff); + track.insert(track.begin() + static_cast(sync_location), extra_data.begin(), extra_data.end()); } }