Merge pull request #61 from mihaip/upstream-imgfile

Move disk image reading to be behind an ImgFile class
This commit is contained in:
dingusdev 2023-11-10 06:29:33 -07:00 committed by GitHub
commit 931060db7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 188 additions and 116 deletions

View File

@ -24,7 +24,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/ata/atahd.h>
#include <cstring>
#include <sys/stat.h>
#include <fstream>
#include <string>
#include <loguru.hpp>
@ -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;

View File

@ -25,8 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define ATA_HARD_DISK_H
#include <devices/common/ata/atabasedevice.h>
#include <utils/imgfile.h>
#include <string>
#include <fstream>
#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];

View File

@ -30,7 +30,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cinttypes>
#include <cstring>
#include <sys/stat.h>
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<uint32_t>(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<uint32_t>(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;

View File

@ -25,9 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define SCSI_CDROM_H
#include <devices/common/scsi/scsi.h>
#include <utils/imgfile.h>
#include <cinttypes>
#include <fstream>
#include <memory>
#include <string>
@ -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;

View File

@ -30,7 +30,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <fstream>
#include <cstring>
#include <sys/stat.h>
#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 = {

View File

@ -25,9 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define SCSI_HD_H
#include <devices/common/scsi/scsi.h>
#include <utils/imgfile.h>
#include <cinttypes>
#include <fstream>
#include <memory>
#include <string>
@ -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;

View File

@ -25,13 +25,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <machines/machineproperties.h>
#include <loguru.hpp>
#include <memaccess.h>
#include <utils/imgfile.h>
#include <cinttypes>
#include <cstring>
#include <fstream>
#include <string>
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;

View File

@ -23,8 +23,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/storage/blockstoragedevice.h>
#include <sys/stat.h>
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;

View File

@ -24,8 +24,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef BLOCK_STORAGE_DEVICE_H
#define BLOCK_STORAGE_DEVICE_H
#include <utils/imgfile.h>
#include <cinttypes>
#include <fstream>
#include <memory>
#include <string>
@ -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

View File

@ -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)

49
utils/imgfile.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/** @file Image file abstraction for floppy, hard drive and CD-ROM images
* (implemented on each platform). */
#ifndef IMGFILE_H
#define IMGFILE_H
#include <cstddef>
#include <memory>
#include <string>
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> impl;
};
#endif // IMGFILE_H

67
utils/imgfile_sdl.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <utils/imgfile.h>
#include <fstream>
class ImgFile::Impl {
public:
std::fstream stream;
};
ImgFile::ImgFile(): impl(std::make_unique<Impl>())
{
}
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();
}