diff --git a/OSBindings/Mac/Clock Signal/Info.plist b/OSBindings/Mac/Clock Signal/Info.plist
index c6ef0500a..20f8b00df 100644
--- a/OSBindings/Mac/Clock Signal/Info.plist
+++ b/OSBindings/Mac/Clock Signal/Info.plist
@@ -386,6 +386,8 @@
Owner
LSTypeIsPackage
+ NSDocumentClass
+ $(PRODUCT_MODULE_NAME).MachineDocument
CFBundleTypeExtensions
@@ -406,6 +408,8 @@
Owner
LSTypeIsPackage
+ NSDocumentClass
+ $(PRODUCT_MODULE_NAME).MachineDocument
CFBundleTypeExtensions
diff --git a/Storage/Disk/DiskImage/Formats/MSA.cpp b/Storage/Disk/DiskImage/Formats/MSA.cpp
index 9e24a87a3..ce7729290 100644
--- a/Storage/Disk/DiskImage/Formats/MSA.cpp
+++ b/Storage/Disk/DiskImage/Formats/MSA.cpp
@@ -8,16 +8,77 @@
#include "MSA.hpp"
+#include "Utility/ImplicitSectors.hpp"
+
using namespace Storage::Disk;
MSA::MSA(const std::string &file_name) :
file_(file_name) {
+ const auto signature = file_.get16be();
+ if(signature != 0x0e0f) throw Error::InvalidFormat;
+
+ sectors_per_track_ = file_.get16be();
+ sides_ = 1 + file_.get16be();
+ starting_track_ = file_.get16be();
+ ending_track_ = file_.get16be();
+
+ // Create the uncompressed track list.
+ while(true) {
+ const auto data_length = file_.get16be();
+ if(file_.eof()) break;
+
+ if(data_length == sectors_per_track_ * 512) {
+ // This is an uncompressed track.
+ uncompressed_tracks_.push_back(file_.read(data_length));
+ } else {
+ // This is an RLE-compressed track.
+ std::vector track;
+ track.reserve(sectors_per_track_ * 512);
+ uint16_t pointer = 0;
+ while(pointer < data_length) {
+ const auto byte = file_.get8();
+
+ // Compression scheme: if the byte E5 is encountered, an RLE run follows.
+ // An RLE run is encoded as the byte to repeat plus a 16-bit repeat count.
+ if(byte != 0xe5) {
+ track.push_back(byte);
+ ++pointer;
+ continue;
+ }
+
+ pointer += 4;
+ if(pointer > data_length) break;
+
+ const auto value = file_.get8();
+ auto count = file_.get16be();
+ while(count--) {
+ track.push_back(value);
+ }
+ }
+
+ if(pointer != data_length || track.size() != sectors_per_track_ * 512) throw Error::InvalidFormat;
+ uncompressed_tracks_.push_back(std::move(track));
+ }
+ }
+
+ if(uncompressed_tracks_.size() != (ending_track_ - starting_track_ + 1)*sides_) throw Error::InvalidFormat;
}
std::shared_ptr<::Storage::Disk::Track> MSA::get_track_at_position(::Storage::Disk::Track::Address address) {
- return nullptr;
+ if(address.head >= sides_) return nullptr;
+
+ const auto position = address.position.as_int();
+ if(position < starting_track_) return nullptr;
+ if(position >= ending_track_) return nullptr;
+
+ const auto &track = uncompressed_tracks_[size_t(position) * size_t(sides_) + size_t(address.head)];
+ return track_for_sectors(track.data(), sectors_per_track_, uint8_t(position), uint8_t(address.head), 0, 2, true);
}
HeadPosition MSA::get_maximum_head_position() {
- return HeadPosition(10);
+ return HeadPosition(ending_track_);
+}
+
+int MSA::get_head_count() {
+ return sides_;
}
diff --git a/Storage/Disk/DiskImage/Formats/MSA.hpp b/Storage/Disk/DiskImage/Formats/MSA.hpp
index 076f85201..5bd8542f0 100644
--- a/Storage/Disk/DiskImage/Formats/MSA.hpp
+++ b/Storage/Disk/DiskImage/Formats/MSA.hpp
@@ -12,6 +12,8 @@
#include "../DiskImage.hpp"
#include "../../../FileHolder.hpp"
+#include
+
namespace Storage {
namespace Disk {
@@ -25,10 +27,17 @@ class MSA final: public DiskImage {
// Implemented to satisfy @c DiskImage.
HeadPosition get_maximum_head_position() override;
+ int get_head_count() override;
std::shared_ptr<::Storage::Disk::Track> get_track_at_position(::Storage::Disk::Track::Address address) override;
private:
FileHolder file_;
+ uint16_t sectors_per_track_;
+ uint16_t sides_;
+ uint16_t starting_track_;
+ uint16_t ending_track_;
+
+ std::vector> uncompressed_tracks_;
};
diff --git a/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp
index 1b3b6ae41..20851efa3 100644
--- a/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp
+++ b/Storage/Disk/DiskImage/Formats/Utility/ImplicitSectors.cpp
@@ -18,7 +18,7 @@
using namespace Storage::Disk;
-std::shared_ptr