From d4c9db7fcf6d944c6af864c68be5c6d38128ce89 Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Sat, 16 Sep 2023 14:17:27 -0700 Subject: [PATCH] Move disk image reading to be behind an ImgFile class Allows different implementations for different platforms (the JS build relies on browser APIs to stream disk images over the network). Setting aside the JS build, this also reduces some code duplication. --- devices/common/ata/atahd.cpp | 21 +++----- devices/common/ata/atahd.h | 5 +- devices/common/scsi/scsicdrom.cpp | 35 ++++++-------- devices/common/scsi/scsicdrom.h | 4 +- devices/common/scsi/scsihd.cpp | 30 ++++-------- devices/common/scsi/scsihd.h | 4 +- devices/floppy/floppyimg.cpp | 60 +++++++++-------------- devices/storage/blockstoragedevice.cpp | 19 +++----- devices/storage/blockstoragedevice.h | 5 +- utils/CMakeLists.txt | 5 +- utils/imgfile.h | 49 +++++++++++++++++++ utils/imgfile_sdl.cpp | 67 ++++++++++++++++++++++++++ 12 files changed, 188 insertions(+), 116 deletions(-) create mode 100644 utils/imgfile.h create mode 100644 utils/imgfile_sdl.cpp diff --git a/devices/common/ata/atahd.cpp b/devices/common/ata/atahd.cpp index d445cb8..abd1592 100644 --- a/devices/common/ata/atahd.cpp +++ b/devices/common/ata/atahd.cpp @@ -24,7 +24,6 @@ along with this program. If not, see . #include #include -#include #include #include #include @@ -35,16 +34,11 @@ AtaHardDisk::AtaHardDisk() : AtaBaseDevice("ATA-HD", DEVICE_TYPE_ATA) { } void AtaHardDisk::insert_image(std::string filename) { - this->hdd_img.open(filename, std::fstream::out | std::fstream::in | std::fstream::binary); - - struct stat stat_buf; - int rc = stat(filename.c_str(), &stat_buf); - if (!rc) { - this->img_size = stat_buf.st_size; - } else { - ABORT_F("AtaHardDisk: could not determine file size using stat()"); + if (!this->hdd_img.open(filename)) { + ABORT_F("AtaHardDisk: could not open image file"); } - this->hdd_img.seekg(0, std::ios_base::beg); + + this->img_size = this->hdd_img.size(); } int AtaHardDisk::perform_command() @@ -56,7 +50,6 @@ int AtaHardDisk::perform_command() case NOP: break; case RECALIBRATE: - hdd_img.seekg(0, std::ios::beg); this->r_error = 0; this->r_cylinder_lo = 0; this->r_cylinder_hi = 0; @@ -68,8 +61,7 @@ int AtaHardDisk::perform_command() uint32_t sector = (r_sect_num << 16); sector |= ((this->r_cylinder_lo) << 8) + (this->r_cylinder_hi); uint64_t offset = sector * ATA_HD_SEC_SIZE; - hdd_img.seekg(offset, std::ios::beg); - hdd_img.read(buffer, sec_count * ATA_HD_SEC_SIZE); + hdd_img.read(buffer, offset, sec_count * ATA_HD_SEC_SIZE); this->r_status &= ~DRQ; } break; @@ -80,8 +72,7 @@ int AtaHardDisk::perform_command() uint32_t sector = (r_sect_num << 16); sector |= ((this->r_cylinder_lo) << 8) + (this->r_cylinder_hi); uint64_t offset = sector * ATA_HD_SEC_SIZE; - hdd_img.seekg(offset, std::ios::beg); - hdd_img.write(buffer, sec_count * ATA_HD_SEC_SIZE); + hdd_img.write(buffer, offset, sec_count * ATA_HD_SEC_SIZE); this->r_status &= ~DRQ; } break; diff --git a/devices/common/ata/atahd.h b/devices/common/ata/atahd.h index fa9ce32..20965a8 100644 --- a/devices/common/ata/atahd.h +++ b/devices/common/ata/atahd.h @@ -25,8 +25,9 @@ along with this program. If not, see . #define ATA_HARD_DISK_H #include +#include + #include -#include #define ATA_HD_SEC_SIZE 512 @@ -40,7 +41,7 @@ public: int perform_command() override; private: - std::fstream hdd_img; + ImgFile hdd_img; uint64_t img_size; char * buffer = new char[1 <<17]; diff --git a/devices/common/scsi/scsicdrom.cpp b/devices/common/scsi/scsicdrom.cpp index 5e74c8d..6b29dd2 100644 --- a/devices/common/scsi/scsicdrom.cpp +++ b/devices/common/scsi/scsicdrom.cpp @@ -30,7 +30,6 @@ along with this program. If not, see . #include #include -#include using namespace std; @@ -50,25 +49,20 @@ ScsiCdrom::ScsiCdrom(int my_id) : ScsiDevice(my_id) void ScsiCdrom::insert_image(std::string filename) { - this->cdr_img.open(filename, ios::out | ios::in | ios::binary); - - struct stat stat_buf; - int rc = stat(filename.c_str(), &stat_buf); - if (!rc) { - this->img_size = stat_buf.st_size; - this->total_frames = (this->img_size + this->sector_size - 1) / this->sector_size; - - // create single track descriptor - this->tracks[0] = {.trk_num = 1, .adr_ctrl = 0x14, .start_lba = 0}; - this->num_tracks = 1; - - // create Lead-out descriptor containing all data - this->tracks[1] = {.trk_num = LEAD_OUT_TRK_NUM, .adr_ctrl = 0x14, - .start_lba = static_cast(this->total_frames)}; - } else { - ABORT_F("SCSI-CDROM: could not determine file size using stat()"); + if (!this->cdr_img.open(filename)) { + ABORT_F("SCSI-CDROM: could not open image file"); } - this->cdr_img.seekg(0, std::ios_base::beg); + + this->img_size = this->cdr_img.size(); + this->total_frames = (this->img_size + this->sector_size - 1) / this->sector_size; + + // create single track descriptor + this->tracks[0] = {.trk_num = 1, .adr_ctrl = 0x14, .start_lba = 0}; + this->num_tracks = 1; + + // create Lead-out descriptor containing all data + this->tracks[1] = {.trk_num = LEAD_OUT_TRK_NUM, .adr_ctrl = 0x14, + .start_lba = static_cast(this->total_frames)}; } void ScsiCdrom::process_command() @@ -155,8 +149,7 @@ void ScsiCdrom::read(const uint32_t lba, const uint16_t transfer_len, const uint transfer_size *= this->sector_size; uint64_t device_offset = lba * this->sector_size; - this->cdr_img.seekg(device_offset, this->cdr_img.beg); - this->cdr_img.read(this->data_buf, transfer_size); + this->cdr_img.read(this->data_buf, device_offset, transfer_size); this->bytes_out = transfer_size; this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE; diff --git a/devices/common/scsi/scsicdrom.h b/devices/common/scsi/scsicdrom.h index bae5834..0859617 100644 --- a/devices/common/scsi/scsicdrom.h +++ b/devices/common/scsi/scsicdrom.h @@ -25,9 +25,9 @@ along with this program. If not, see . #define SCSI_CDROM_H #include +#include #include -#include #include #include @@ -74,7 +74,7 @@ private: AddrMsf lba_to_msf(const int lba); private: - std::fstream cdr_img; + ImgFile cdr_img; uint64_t img_size; int total_frames; int num_tracks; diff --git a/devices/common/scsi/scsihd.cpp b/devices/common/scsi/scsihd.cpp index 695636e..d17c559 100644 --- a/devices/common/scsi/scsihd.cpp +++ b/devices/common/scsi/scsihd.cpp @@ -30,7 +30,6 @@ along with this program. If not, see . #include #include -#include #define HDD_SECTOR_SIZE 512 @@ -43,17 +42,12 @@ ScsiHardDisk::ScsiHardDisk(int my_id) : ScsiDevice(my_id) { void ScsiHardDisk::insert_image(std::string filename) { //We don't want to store everything in memory, but //we want to keep the hard disk available. - this->hdd_img.open(filename, ios::out | ios::in | ios::binary); - - struct stat stat_buf; - int rc = stat(filename.c_str(), &stat_buf); - if (!rc) { - this->img_size = stat_buf.st_size; - this->total_blocks = (this->img_size + HDD_SECTOR_SIZE - 1) / HDD_SECTOR_SIZE; - } else { - ABORT_F("ScsiHardDisk: could not determine file size using stat()"); + if (!this->hdd_img.open(filename)) { + ABORT_F("ScsiHardDisk: could not open image file"); } - this->hdd_img.seekg(0, std::ios_base::beg); + + this->img_size = this->hdd_img.size(); + this->total_blocks = (this->img_size + HDD_SECTOR_SIZE - 1) / HDD_SECTOR_SIZE; } void ScsiHardDisk::process_command() { @@ -267,8 +261,7 @@ void ScsiHardDisk::read(uint32_t lba, uint16_t transfer_len, uint8_t cmd_len) { transfer_size *= HDD_SECTOR_SIZE; uint64_t device_offset = lba * HDD_SECTOR_SIZE; - this->hdd_img.seekg(device_offset, this->hdd_img.beg); - this->hdd_img.read(img_buffer, transfer_size); + this->hdd_img.read(img_buffer, device_offset, transfer_size); this->cur_buf_cnt = transfer_size; this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE; @@ -288,20 +281,17 @@ void ScsiHardDisk::write(uint32_t lba, uint16_t transfer_len, uint8_t cmd_len) { this->incoming_size = transfer_size; - this->hdd_img.seekg(device_offset, this->hdd_img.beg); - - this->post_xfer_action = [this]() { - this->hdd_img.write(this->img_buffer, this->incoming_size); + this->post_xfer_action = [this, device_offset]() { + this->hdd_img.write(this->img_buffer, device_offset, this->incoming_size); }; } void ScsiHardDisk::seek(uint32_t lba) { - uint64_t device_offset = lba * HDD_SECTOR_SIZE; - this->hdd_img.seekg(device_offset, this->hdd_img.beg); + // No-op } void ScsiHardDisk::rewind() { - this->hdd_img.seekg(0, this->hdd_img.beg); + // No-op } static const PropMap SCSI_HD_Properties = { diff --git a/devices/common/scsi/scsihd.h b/devices/common/scsi/scsihd.h index 98f7118..fc8f168 100644 --- a/devices/common/scsi/scsihd.h +++ b/devices/common/scsi/scsihd.h @@ -25,9 +25,9 @@ along with this program. If not, see . #define SCSI_HD_H #include +#include #include -#include #include #include @@ -60,7 +60,7 @@ protected: void rewind(); private: - std::fstream hdd_img; + ImgFile hdd_img; uint64_t img_size; int total_blocks; uint64_t file_offset = 0; diff --git a/devices/floppy/floppyimg.cpp b/devices/floppy/floppyimg.cpp index 59ab541..4e0d3cf 100644 --- a/devices/floppy/floppyimg.cpp +++ b/devices/floppy/floppyimg.cpp @@ -25,13 +25,13 @@ along with this program. If not, see . #include #include #include +#include #include #include -#include #include -static FlopImgType identify_image(std::ifstream& img_file) +static FlopImgType identify_image(ImgFile& img_file) { // WOZ images identification strings static uint8_t WOZ1_SIG[] = {0x57, 0x4F, 0x5A, 0x31, 0xFF, 0x0A, 0x0D, 0x0A}; @@ -39,8 +39,7 @@ static FlopImgType identify_image(std::ifstream& img_file) uint8_t buf[8] = { 0 }; - img_file.seekg(0, std::ios::beg); - img_file.read((char *)buf, sizeof(buf)); + img_file.read((char *)buf, 0, sizeof(buf)); // WOZ files are easily identified if (!std::memcmp(buf, WOZ1_SIG, sizeof(buf))) { @@ -50,8 +49,7 @@ static FlopImgType identify_image(std::ifstream& img_file) } else { for (int offset = 0; offset <=84; offset += 84) { // rewind to logical block 2 - img_file.seekg(2*BLOCK_SIZE + offset, std::ios::beg); - img_file.read((char *)buf, sizeof(buf)); + img_file.read((char *)buf, 2*BLOCK_SIZE + offset, sizeof(buf)); // check for HFS/MFS signature at the start of the logical block 2 if ((buf[0] == 0x42 && buf[1] == 0x44) || @@ -79,26 +77,22 @@ RawFloppyImg::RawFloppyImg(std::string& file_path) : FloppyImgConverter() */ int RawFloppyImg::calc_phys_params() { - std::ifstream img_file; + ImgFile img_file; - img_file.open(img_path, std::ios::in | std::ios::binary); - if (img_file.fail()) { + if (!img_file.open(img_path)) { img_file.close(); LOG_F(ERROR, "RawFloppyImg: Could not open specified floppy image!"); return -1; } // determine image size - img_file.seekg(0, img_file.end); - size_t img_size = img_file.tellg(); + size_t img_size = img_file.size(); + img_file.close(); if (img_size > 2*1024*1024) { LOG_F(ERROR, "RawFloppyImg: image size is too large to determine disk format from image size!"); return -1; } this->img_size = (int)img_size; - img_file.seekg(0, img_file.beg); - - img_file.close(); // verify image size if (this->img_size < 5*BLOCK_SIZE) { @@ -177,17 +171,15 @@ int RawFloppyImg::calc_phys_params() /** Retrieve raw disk data. */ int RawFloppyImg::get_raw_disk_data(char* buf) { - std::ifstream img_file; + ImgFile img_file; - img_file.open(img_path, std::ios::in | std::ios::binary); - if (img_file.fail()) { + if (!img_file.open(img_path)) { img_file.close(); LOG_F(ERROR, "RawFloppyImg: Could not open specified floppy image!"); return -1; } - img_file.seekg(0, img_file.beg); - img_file.read(buf, this->data_size); + img_file.read(buf, 0, this->data_size); img_file.close(); return 0; @@ -206,24 +198,20 @@ DiskCopy42Img::DiskCopy42Img(std::string& file_path) : FloppyImgConverter() } int DiskCopy42Img::calc_phys_params() { - std::ifstream img_file; + ImgFile img_file; - img_file.open(img_path, std::ios::in | std::ios::binary); - if (img_file.fail()) { + if (!img_file.open(img_path)) { img_file.close(); LOG_F(ERROR, "DiskCopy42Img: could not open specified floppy image!"); return -1; } // determine image size - img_file.seekg(0, img_file.end); - size_t img_size = img_file.tellg(); - img_file.seekg(0, img_file.beg); + size_t img_size = img_file.size(); // get data size from image uint8_t buf[4]; - img_file.seekg(0x40, img_file.beg); - img_file.read((char *)&buf, 4); + img_file.read((char *)&buf, 0x40, 4); this->data_size = READ_DWORD_BE_U(buf); if (this->data_size > img_size) { @@ -235,9 +223,8 @@ int DiskCopy42Img::calc_phys_params() { uint8_t disk_format = 0xFFU; - img_file.seekg(0x50, img_file.beg); - img_file.read((char *)&disk_format, 1); - img_file.read((char *)&this->format_byte, 1); + img_file.read((char *)&disk_format, 0x50, 1); + img_file.read((char *)&this->format_byte, 0x51, 1); img_file.close(); @@ -272,17 +259,15 @@ int DiskCopy42Img::calc_phys_params() { } int DiskCopy42Img::get_raw_disk_data(char* buf) { - std::ifstream img_file; + ImgFile img_file; - img_file.open(img_path, std::ios::in | std::ios::binary); - if (img_file.fail()) { + if (!img_file.open(img_path)) { img_file.close(); LOG_F(ERROR, "DiskCopy42Img: could not open specified floppy image!"); return -1; } - img_file.seekg(0x54, img_file.beg); - img_file.read(buf, this->data_size); + img_file.read(buf, 0x54, this->data_size); img_file.close(); return 0; @@ -296,10 +281,9 @@ FloppyImgConverter* open_floppy_image(std::string& img_path) { FloppyImgConverter *fconv = nullptr; - std::ifstream img_file; + ImgFile img_file; - img_file.open(img_path, std::ios::in | std::ios::binary); - if (img_file.fail()) { + if (!img_file.open(img_path)) { img_file.close(); LOG_F(ERROR, "Could not open specified floppy image (%s)!", img_path.c_str()); return nullptr; diff --git a/devices/storage/blockstoragedevice.cpp b/devices/storage/blockstoragedevice.cpp index 52379b3..e797aa1 100644 --- a/devices/storage/blockstoragedevice.cpp +++ b/devices/storage/blockstoragedevice.cpp @@ -23,8 +23,6 @@ along with this program. If not, see . #include -#include - using namespace std; BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks, const uint32_t block_size) { @@ -36,21 +34,17 @@ BlockStorageDevice::BlockStorageDevice(const uint32_t cache_blocks, const uint32 } BlockStorageDevice::~BlockStorageDevice() { - if (this->img_file) - this->img_file.close(); + this->img_file.close(); } int BlockStorageDevice::set_host_file(std::string file_path) { this->is_ready = false; - this->img_file.open(file_path, ios::out | ios::in | ios::binary); - - struct stat stat_buf; - int rc = stat(file_path.c_str(), &stat_buf); - if (rc) + if (!this->img_file.open(file_path)) { return -1; + } - this->size_bytes = stat_buf.st_size; + this->size_bytes = this->img_file.size(); this->size_blocks = this->size_bytes / this->block_size; this->set_fpos(0); @@ -61,7 +55,6 @@ int BlockStorageDevice::set_host_file(std::string file_path) { int BlockStorageDevice::set_fpos(const uint32_t lba) { this->cur_fpos = lba * this->block_size; - this->img_file.seekg(this->cur_fpos, this->img_file.beg); return 0; } @@ -75,7 +68,7 @@ int BlockStorageDevice::read_begin(int nblocks, uint32_t max_len) { this->remain_size = 0; } - this->img_file.read(this->data_cache.get(), read_size); + this->img_file.read(this->data_cache.get(), this->cur_fpos, read_size); this->cur_fpos += read_size; return read_size; @@ -95,7 +88,7 @@ int BlockStorageDevice::read_more() { this->remain_size = 0; } - this->img_file.read(this->data_cache.get(), read_size); + this->img_file.read(this->data_cache.get(), this->cur_fpos, read_size); this->cur_fpos += read_size; return read_size; diff --git a/devices/storage/blockstoragedevice.h b/devices/storage/blockstoragedevice.h index 858f98c..3a93270 100644 --- a/devices/storage/blockstoragedevice.h +++ b/devices/storage/blockstoragedevice.h @@ -24,8 +24,9 @@ along with this program. If not, see . #ifndef BLOCK_STORAGE_DEVICE_H #define BLOCK_STORAGE_DEVICE_H +#include + #include -#include #include #include @@ -45,7 +46,7 @@ public: int write_begin(char *buf, int nblocks); protected: - std::fstream img_file = {}; + ImgFile img_file; uint64_t size_bytes = 0; // image file size in bytes uint64_t size_blocks = 0; // image file size in blocks uint64_t cur_fpos = 0; // current image file pointer position diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 6010b1f..fa593ad 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -1,6 +1,9 @@ +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +include(PlatformGlob) + include_directories("${PROJECT_SOURCE_DIR}") -file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") add_library(utils OBJECT ${SOURCES}) target_link_libraries(utils PRIVATE) diff --git a/utils/imgfile.h b/utils/imgfile.h new file mode 100644 index 0000000..cb72e5f --- /dev/null +++ b/utils/imgfile.h @@ -0,0 +1,49 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-23 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/** @file Image file abstraction for floppy, hard drive and CD-ROM images + * (implemented on each platform). */ + +#ifndef IMGFILE_H +#define IMGFILE_H + +#include +#include +#include + +class ImgFile { +public: + ImgFile(); + ~ImgFile(); + + bool open(const std::string& img_path); + void close(); + + size_t size() const; + + size_t read(void* buf, off_t offset, size_t length) const; + size_t write(const void* buf, off_t offset, size_t length); +private: + class Impl; // Holds private fields + std::unique_ptr impl; +}; + +#endif // IMGFILE_H diff --git a/utils/imgfile_sdl.cpp b/utils/imgfile_sdl.cpp new file mode 100644 index 0000000..4f7a155 --- /dev/null +++ b/utils/imgfile_sdl.cpp @@ -0,0 +1,67 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-23 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include + +#include + +class ImgFile::Impl { +public: + std::fstream stream; +}; + +ImgFile::ImgFile(): impl(std::make_unique()) +{ + +} + +ImgFile::~ImgFile() = default; + +bool ImgFile::open(const std::string &img_path) +{ + impl->stream.open(img_path, std::ios::in | std::ios::out | std::ios::binary); + return !impl->stream.fail(); +} + +void ImgFile::close() +{ + impl->stream.close(); +} + +size_t ImgFile::size() const +{ + impl->stream.seekg(0, impl->stream.end); + return impl->stream.tellg(); +} + +size_t ImgFile::read(void* buf, off_t offset, size_t length) const +{ + impl->stream.seekg(offset, std::ios::beg); + impl->stream.read((char *)buf, length); + return impl->stream.gcount(); +} + +size_t ImgFile::write(const void* buf, off_t offset, size_t length) +{ + impl->stream.seekg(offset, std::ios::beg); + impl->stream.write((const char *)buf, length); + return impl->stream.gcount(); +}