diff --git a/Analyser/Static/StaticAnalyser.cpp b/Analyser/Static/StaticAnalyser.cpp index 5a0a7996d..589f3f206 100644 --- a/Analyser/Static/StaticAnalyser.cpp +++ b/Analyser/Static/StaticAnalyser.cpp @@ -55,6 +55,7 @@ // Mass Storage Devices (i.e. usually, hard disks) #include "../../Storage/MassStorage/Formats/DAT.hpp" +#include "../../Storage/MassStorage/Formats/DSK.hpp" #include "../../Storage/MassStorage/Formats/HFV.hpp" // State Snapshots @@ -144,7 +145,8 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform:: TargetPlatform::AmstradCPC | TargetPlatform::Oric | TargetPlatform::ZXSpectrum) // DSK (Amstrad CPC, etc) Format("dsk", result.disks, Disk::DiskImageHolder, TargetPlatform::DiskII) // DSK (Apple II) Format("dsk", result.disks, Disk::DiskImageHolder, TargetPlatform::Macintosh) // DSK (Macintosh, floppy disk) - Format("dsk", result.mass_storage_devices, MassStorage::HFV, TargetPlatform::Macintosh) // DSK (Macintosh, hard disk) + Format("dsk", result.mass_storage_devices, MassStorage::HFV, TargetPlatform::Macintosh) // DSK (Macintosh, hard disk, single volume image) + Format("dsk", result.mass_storage_devices, MassStorage::DSK, TargetPlatform::Macintosh) // DSK (Macintosh, hard disk, full device image) Format("dsk", result.disks, Disk::DiskImageHolder, TargetPlatform::MSX) // DSK (MSX) Format("dsk", result.disks, Disk::DiskImageHolder, TargetPlatform::Oric) // DSK (Oric) Format("g64", result.disks, Disk::DiskImageHolder, TargetPlatform::Commodore) // G64 diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 2fc24652f..bde5d0985 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -551,6 +551,8 @@ 4B92E26B234AE35100CD6D1B /* MFP68901.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B92E268234AE35000CD6D1B /* MFP68901.cpp */; }; 4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; }; 4B9378E422A199C600973513 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9378E222A199C600973513 /* Audio.cpp */; }; + 4B96F7CE263E33B10092AEE1 /* DSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96F7CC263E33B10092AEE1 /* DSK.cpp */; }; + 4B96F7CF263E33B10092AEE1 /* DSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B96F7CC263E33B10092AEE1 /* DSK.cpp */; }; 4B98A05E1FFAD3F600ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; }; 4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; }; 4B98A0611FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */; }; @@ -1524,6 +1526,9 @@ 4B9378E322A199C600973513 /* Audio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Audio.hpp; sourceTree = ""; }; 4B95FA9C1F11893B0008E395 /* ZX8081OptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZX8081OptionsPanel.swift; sourceTree = ""; }; 4B961408222760E0001A7BF2 /* Screenshot.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Screenshot.hpp; sourceTree = ""; }; + 4B96F7CB263E30B00092AEE1 /* RawSectorDump.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RawSectorDump.hpp; sourceTree = ""; }; + 4B96F7CC263E33B10092AEE1 /* DSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DSK.cpp; sourceTree = ""; }; + 4B96F7CD263E33B10092AEE1 /* DSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DSK.hpp; sourceTree = ""; }; 4B98A05C1FFAD3F600ADF63B /* CSROMFetcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CSROMFetcher.hpp; sourceTree = ""; }; 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CSROMFetcher.mm; sourceTree = ""; }; 4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MSXStaticAnalyserTests.mm; sourceTree = ""; }; @@ -2969,10 +2974,13 @@ 4B74CF7E2312FA9C00500CE8 /* Formats */ = { isa = PBXGroup; children = ( - 4B74CF7F2312FA9C00500CE8 /* HFV.hpp */, - 4B74CF802312FA9C00500CE8 /* HFV.cpp */, 4BE8EB6425C750B50040BC40 /* DAT.cpp */, 4BE8EB6525C750B50040BC40 /* DAT.hpp */, + 4B96F7CC263E33B10092AEE1 /* DSK.cpp */, + 4B96F7CD263E33B10092AEE1 /* DSK.hpp */, + 4B74CF802312FA9C00500CE8 /* HFV.cpp */, + 4B74CF7F2312FA9C00500CE8 /* HFV.hpp */, + 4B96F7CB263E30B00092AEE1 /* RawSectorDump.hpp */, ); path = Formats; sourceTree = ""; @@ -5238,6 +5246,7 @@ 4B1B58F7246CC4E8009C171E /* State.cpp in Sources */, 4B0ACC03237756F6008902D0 /* Line.cpp in Sources */, 4B055AB11FAE86070060FFFF /* Tape.cpp in Sources */, + 4B96F7CF263E33B10092AEE1 /* DSK.cpp in Sources */, 4B2B946626377C0200E7097C /* SZX.cpp in Sources */, 4BEDA43225B3C700000C2DBD /* Executor.cpp in Sources */, 4BC1317B2346DF2B00E4FF3D /* MSA.cpp in Sources */, @@ -5544,6 +5553,7 @@ 4B89453E201967B4007DE474 /* StaticAnalyser.cpp in Sources */, 4BF8D4D5251C11DD00BBE21B /* 65816Storage.cpp in Sources */, 4B0ACC2823775819008902D0 /* DMAController.cpp in Sources */, + 4B96F7CE263E33B10092AEE1 /* DSK.cpp in Sources */, 4BC131702346DE5000E4FF3D /* StaticAnalyser.cpp in Sources */, 4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */, 4BCE0053227CE8CA000CA200 /* AppleII.cpp in Sources */, diff --git a/Storage/MassStorage/Formats/DAT.cpp b/Storage/MassStorage/Formats/DAT.cpp index ceb00c7ab..d5853dfd6 100644 --- a/Storage/MassStorage/Formats/DAT.cpp +++ b/Storage/MassStorage/Formats/DAT.cpp @@ -10,32 +10,13 @@ using namespace Storage::MassStorage; -DAT::DAT(const std::string &file_name) : file_(file_name) { - // Is the file a multiple of 256 bytes in size? - const auto file_size = file_.stats().st_size; - if(file_size & 255) throw std::exception(); - - // Does it contain the 'Hugo' signature? - file_.seek(0x201, SEEK_SET); - if(!file_.check_signature("Hugo")) { +DAT::DAT(const std::string &file_name) : RawSectorDump(file_name) { + // Does the third sector contain the 'Hugo' signature? + const auto sector3 = get_block(2); + if(sector3.size() != 256) { + throw std::exception(); + } + if(sector3[1] != 'H' || sector3[2] != 'u' || sector3[3] != 'g' || sector3[4] != 'o') { throw std::exception(); } } - -size_t DAT::get_block_size() { - return 256; -} - -size_t DAT::get_number_of_blocks() { - return size_t(file_.stats().st_size) / 256; -} - -std::vector DAT::get_block(size_t address) { - file_.seek(long(address * 256), SEEK_SET); - return file_.read(256); -} - -void DAT::set_block(size_t address, const std::vector &contents) { - file_.seek(long(address * 256), SEEK_SET); - file_.write(contents); -} diff --git a/Storage/MassStorage/Formats/DAT.hpp b/Storage/MassStorage/Formats/DAT.hpp index 7ec0350e4..a47a537c5 100644 --- a/Storage/MassStorage/Formats/DAT.hpp +++ b/Storage/MassStorage/Formats/DAT.hpp @@ -9,8 +9,7 @@ #ifndef MassStorage_DAT_hpp #define MassStorage_DAT_hpp -#include "../MassStorageDevice.hpp" -#include "../../FileHolder.hpp" +#include "RawSectorDump.hpp" namespace Storage { namespace MassStorage { @@ -20,18 +19,9 @@ namespace MassStorage { sector dump of an ADFS volume. It will be validated for an ADFS catalogue and communicate in 256-byte blocks. */ -class DAT: public MassStorageDevice { +class DAT: public RawSectorDump<256> { public: DAT(const std::string &file_name); - - private: - FileHolder file_; - - /* MassStorageDevices overrides. */ - size_t get_block_size() final; - size_t get_number_of_blocks() final; - std::vector get_block(size_t address) final; - void set_block(size_t address, const std::vector &) final; }; } diff --git a/Storage/MassStorage/Formats/DSK.cpp b/Storage/MassStorage/Formats/DSK.cpp new file mode 100644 index 000000000..231855546 --- /dev/null +++ b/Storage/MassStorage/Formats/DSK.cpp @@ -0,0 +1,23 @@ +// +// DSK.cpp +// Clock Signal +// +// Created by Thomas Harte on 01/05/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#include "DSK.hpp" + +using namespace Storage::MassStorage; + +DSK::DSK(const std::string &file_name) : RawSectorDump(file_name) { + // Minimum validation: check the first sector for a device signature, + // with 512-byte blocks. + const auto sector = get_block(0); + if(sector.size() != 512) { + throw std::exception(); + } + if(sector[0] != 0x45 || sector[1] != 0x52 || sector[2] != 0x02 || sector[3] != 0x00) { + throw std::exception(); + } +} diff --git a/Storage/MassStorage/Formats/DSK.hpp b/Storage/MassStorage/Formats/DSK.hpp new file mode 100644 index 000000000..bdf1b53cc --- /dev/null +++ b/Storage/MassStorage/Formats/DSK.hpp @@ -0,0 +1,30 @@ +// +// DSK.hpp +// Clock Signal +// +// Created by Thomas Harte on 01/05/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#ifndef MassStorage_DSK_hpp +#define MassStorage_DSK_hpp + +#include "RawSectorDump.hpp" + +namespace Storage { +namespace MassStorage { + +/*! + Provides a @c MassStorageDevice containing a Macintosh DSK image, which is just a + sector dump of an entire HFS drive. It will be validated for an Apple-style partition map and communicate + in 512-byte blocks. +*/ +class DSK: public RawSectorDump<512> { + public: + DSK(const std::string &file_name); +}; + +} +} + +#endif /* MassStorage_DSK_hpp */ diff --git a/Storage/MassStorage/Formats/HFV.cpp b/Storage/MassStorage/Formats/HFV.cpp index 3e454e892..f4e3b9ae0 100644 --- a/Storage/MassStorage/Formats/HFV.cpp +++ b/Storage/MassStorage/Formats/HFV.cpp @@ -15,7 +15,10 @@ HFV::HFV(const std::string &file_name) : file_(file_name) { const auto file_size = file_.stats().st_size; if(file_size & 511 || file_size <= 800*1024) throw std::exception(); - // TODO: check filing system for MFS, HFS or HFS+. + // Is this an HFS volume? + // TODO: check filing system for MFS or HFS+. + const auto prefix = file_.read(2); + if(prefix[0] != 'L' || prefix[1] != 'K') throw std::exception(); } size_t HFV::get_block_size() { diff --git a/Storage/MassStorage/Formats/RawSectorDump.hpp b/Storage/MassStorage/Formats/RawSectorDump.hpp new file mode 100644 index 000000000..60d0e7314 --- /dev/null +++ b/Storage/MassStorage/Formats/RawSectorDump.hpp @@ -0,0 +1,55 @@ +// +// RawSectorDump.hpp +// Clock Signal +// +// Created by Thomas Harte on 01/05/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#ifndef RawSectorDump_h +#define RawSectorDump_h + +#include "../MassStorageDevice.hpp" +#include "../../FileHolder.hpp" + +#include + +namespace Storage { +namespace MassStorage { + +template class RawSectorDump: public MassStorageDevice { + public: + RawSectorDump(const std::string &file_name) : file_(file_name) { + // Is the file a multiple of sector_size bytes in size? + const auto file_size = size_t(file_.stats().st_size); + if(file_size % sector_size) throw std::exception(); + } + + /* MassStorageDevices overrides. */ + size_t get_block_size() final { + return sector_size; + } + + size_t get_number_of_blocks() final { + return size_t(file_.stats().st_size) / sector_size; + } + + std::vector get_block(size_t address) final { + file_.seek(long(address * sector_size), SEEK_SET); + return file_.read(sector_size); + } + + void set_block(size_t address, const std::vector &contents) final { + assert(contents.size() == sector_size); + file_.seek(long(address * sector_size), SEEK_SET); + file_.write(contents); + } + + private: + FileHolder file_; +}; + +} +} + +#endif /* RawSectorDump_h */ diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index f6944d2f0..a6d99ccc2 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -19,7 +19,7 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond if(!device_) return false; const auto specs = state.read_write_specs(); - LOG("Read: " << specs.number_of_blocks << " from " << specs.address); + LOG("Read: " << std::dec << specs.number_of_blocks << " from " << specs.address); std::vector output = device_->get_block(specs.address); for(uint32_t offset = 1; offset < specs.number_of_blocks; ++offset) {