diff --git a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp index 91882590d..d4184a849 100644 --- a/Storage/Disk/DiskImage/Formats/AppleDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/AppleDSK.cpp @@ -9,7 +9,9 @@ #include "AppleDSK.hpp" #include "../../Track/PCMTrack.hpp" +#include "../../Track/TrackSerialiser.hpp" #include "../../Encodings/AppleGCR/Encoder.hpp" +#include "../../Encodings/AppleGCR/SegmentParser.hpp" using namespace Storage::Disk; @@ -42,10 +44,21 @@ HeadPosition AppleDSK::get_maximum_head_position() { return HeadPosition(number_of_tracks); } +bool AppleDSK::get_is_read_only() { + return file_.get_is_known_read_only(); +} + +long AppleDSK::file_offset(Track::Address address) { + return address.position.as_int() * bytes_per_sector * sectors_per_track_; +} + std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { - const long file_offset = address.position.as_int() * bytes_per_sector * sectors_per_track_; - file_.seek(file_offset, SEEK_SET); - const std::vector track_data = file_.read(static_cast(bytes_per_sector * sectors_per_track_)); + std::vector track_data; + { + std::lock_guard lock_guard(file_.get_file_access_mutex()); + file_.seek(file_offset(address), SEEK_SET); + track_data = file_.read(static_cast(bytes_per_sector * sectors_per_track_)); + } Storage::Disk::PCMSegment segment; const uint8_t track = static_cast(address.position.as_int()); @@ -71,8 +84,36 @@ std::shared_ptr AppleDSK::get_track_at_position(Track::Address address) { segment += Encodings::AppleGCR::six_and_two_sync((50000 - segment.number_of_bits) / 10); } } else { - + // TODO: 5 and 3, 13-sector format. If DSK actually supports it? } return std::make_shared(segment); } + +void AppleDSK::set_tracks(const std::map> &tracks) { + std::map> tracks_by_address; + for(const auto &pair: tracks) { + // Decode the track. + auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment( + Storage::Disk::track_serialisation(*pair.second, Storage::Time(1, 50000))); + + // Rearrange sectors into Apple DOS or Pro-DOS order. + std::vector track_contents(static_cast(bytes_per_sector * sectors_per_track_)); + for(const auto §or_pair: sector_map) { + size_t target_address = sector_pair.second.address.sector; + if(target_address != 15) { + target_address = (target_address * (is_prodos_ ? 2 : 13)) % 15; + } + memcpy(&track_contents[target_address*256], sector_pair.second.data.data(), bytes_per_sector); + } + + // Store for later. + tracks_by_address[pair.first] = std::move(track_contents); + } + + std::lock_guard lock_guard(file_.get_file_access_mutex()); + for(const auto &pair: tracks_by_address) { + file_.seek(file_offset(pair.first), SEEK_SET); + file_.write(pair.second); + } +} diff --git a/Storage/Disk/DiskImage/Formats/AppleDSK.hpp b/Storage/Disk/DiskImage/Formats/AppleDSK.hpp index fb17f359e..14f1f5735 100644 --- a/Storage/Disk/DiskImage/Formats/AppleDSK.hpp +++ b/Storage/Disk/DiskImage/Formats/AppleDSK.hpp @@ -34,14 +34,15 @@ class AppleDSK: public DiskImage { // implemented to satisfy @c Disk HeadPosition get_maximum_head_position() override; std::shared_ptr get_track_at_position(Track::Address address) override; - - // TEST! - bool get_is_read_only() override { return false; } + void set_tracks(const std::map> &tracks) override; + bool get_is_read_only() override; private: Storage::FileHolder file_; int sectors_per_track_ = 16; bool is_prodos_ = false; + + long file_offset(Track::Address address); }; }