diff options
author | 2021-08-22 09:06:15 +1000 | |
---|---|---|
committer | 2021-08-22 09:06:15 +1000 | |
commit | e8bbea1fc6e94e14768509d322f6c624403ffb36 (patch) | |
tree | 74dd1606a900d83de8aecff17a6737af4113308d /src/lib | |
parent | e319bde5fc3696d7f48f62b15b6366c4377fe5d1 (diff) |
formats, osd, util: Started refactoring file I/O stuff. (#8456)
Added more modern generic I/O interfaces with implementation backed by stdio, osd_file and core_file, replacing io_generic. Also replaced core_file's build-in zlib compression with a filter.
unzip.cpp, un7z.cpp: Added option to supply abstract I/O interface rather than filename.
Converted osd_file, core_file, archive_file, chd_file and device_image_interface to use std::error_condition rather than their own error enums.
Allow mounting TI-99 RPK from inside archives.
Diffstat (limited to 'src/lib')
169 files changed, 6360 insertions, 3645 deletions
diff --git a/src/lib/formats/acorn_dsk.cpp b/src/lib/formats/acorn_dsk.cpp index c4668478b05..40ab6eb1029 100644 --- a/src/lib/formats/acorn_dsk.cpp +++ b/src/lib/formats/acorn_dsk.cpp @@ -10,6 +10,9 @@ #include "acorn_dsk.h" +#include "ioprocs.h" + + acorn_ssd_format::acorn_ssd_format() : wd177x_format(formats) { } @@ -29,29 +32,36 @@ const char *acorn_ssd_format::extensions() const return "ssd,bbc,img"; } -int acorn_ssd_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_ssd_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t cat[8]; uint32_t sectors0, sectors2; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("ssd: error getting image size\n"); + return -1; + } - for(int i=0; formats[i].form_factor; i++) { + for (int i=0; formats[i].form_factor; i++) + { + size_t actual; const format &f = formats[i]; - if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) + if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; // test for Torch CPN - test pattern at sector &0018 - io_generic_read(io, cat, 0x32800, 8); + io.read_at(0x32800, cat, 8, actual); if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // test for HADFS - test pattern at sector 70 - io_generic_read(io, cat, 0x04610, 8); + io.read_at(0x04610, cat, 8, actual); if (memcmp(cat, "\x00\x28\x43\x29\x4a\x47\x48\x00", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // test for Kenda SD - offset &0962 = 0 SD/1 DD, offset &0963 = disk size blocks / 4 (block size = 1K, ie. 0x400 bytes), reserved tracks = 3, ie. 0x1e00 bytes, soft stagger = 2 sectors, ie. 0x200 bytes - io_generic_read(io, cat, 0x0960, 8); + io.read_at(0x0960, cat, 8, actual); if (cat[2] == 0 && ((uint64_t)cat[3] * 4 * 0x400 + 0x2000) == size && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) { // valid blocks for single sided @@ -63,20 +73,22 @@ int acorn_ssd_format::find_size(io_generic *io, uint32_t form_factor, const std: } // read sector count from side 0 catalogue - io_generic_read(io, cat, 0x100, 8); + io.read_at(0x100, cat, 8, actual); sectors0 = ((cat[6] & 3) << 8) + cat[7]; LOG_FORMATS("ssd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : ""); - if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) { + if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) + { if (f.head_count == 2) { // read sector count from side 2 catalogue - io_generic_read(io, cat, (uint64_t)compute_track_size(f) * f.track_count + 0x100, 8); // sequential + io.read_at((uint64_t)compute_track_size(f) * f.track_count + 0x100, cat, 8, actual); // sequential sectors2 = ((cat[6] & 3) << 8) + cat[7]; // exception case for Acorn CP/M System Disc 1 - io_generic_read(io, cat, 0x367ec, 8); - if (memcmp(cat, "/M ", 4) == 0) sectors2 = ((cat[6] & 3) << 8) + cat[7]; + io.read_at(0x367ec, cat, 8, actual); + if (memcmp(cat, "/M ", 4) == 0) + sectors2 = ((cat[6] & 3) << 8) + cat[7]; LOG_FORMATS("ssd: sector count 2: %d %s\n", sectors2, sectors2 % 10 != 0 ? "invalid" : ""); } @@ -93,12 +105,13 @@ int acorn_ssd_format::find_size(io_generic *io, uint32_t form_factor, const std: return -1; } -int acorn_ssd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_ssd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); - if(type != -1) + if (type != -1) return 90; + return 0; } @@ -171,40 +184,49 @@ const char *acorn_dsd_format::extensions() const return "dsd"; } -int acorn_dsd_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_dsd_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t cat[8]; uint32_t sectors0, sectors2; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("dsd: error getting image size\n"); + return -1; + } - for (int i = 0; formats[i].form_factor; i++) { + for (int i = 0; formats[i].form_factor; i++) + { + size_t actual; const format &f = formats[i]; if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; // test for Torch CPN - test pattern at sector &0018 - io_generic_read(io, cat, 0x1200, 8); + io.read_at(0x1200, cat, 8, actual); if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // test for HADFS - test pattern at sector 70 - io_generic_read(io, cat, 0x08c10, 8); + io.read_at(0x08c10, cat, 8, actual); if (memcmp(cat, "\x00\x28\x43\x29\x4a\x47\x48\x00", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // read sector count from side 0 catalogue - io_generic_read(io, cat, 0x100, 8); + io.read_at(0x100, cat, 8, actual); sectors0 = ((cat[6] & 3) << 8) + cat[7]; LOG_FORMATS("dsd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : ""); - if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) { + if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) + { // read sector count from side 2 catalogue - io_generic_read(io, cat, 0xb00, 8); // interleaved + io.read_at(0xb00, cat, 8, actual); // interleaved sectors2 = ((cat[6] & 3) << 8) + cat[7]; // exception case for Acorn CP/M System Disc 1 - io_generic_read(io, cat, 0x97ec, 8); - if (memcmp(cat, "/M ", 4) == 0) sectors2 = ((cat[6] & 3) << 8) + cat[7]; + io.read_at(0x97ec, cat, 8, actual); + if (memcmp(cat, "/M ", 4) == 0) + sectors2 = ((cat[6] & 3) << 8) + cat[7]; LOG_FORMATS("dsd: sector count 2: %d %s\n", sectors2, sectors2 % 10 != 0 ? "invalid" : ""); @@ -216,12 +238,13 @@ int acorn_dsd_format::find_size(io_generic *io, uint32_t form_factor, const std: return -1; } -int acorn_dsd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_dsd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); if (type != -1) return 90; + return 0; } @@ -274,27 +297,36 @@ const char *opus_ddos_format::extensions() const return "dds"; } -int opus_ddos_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int opus_ddos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t cat[8]; uint32_t sectors0, sectors2; // read sector count from side 0 catalogue - io_generic_read(io, cat, 0x1000, 8); + io.read_at(0x1000, cat, 8, actual); sectors0 = (cat[1] << 8) + cat[2]; LOG_FORMATS("ddos: sector count 0: %d %s\n", sectors0, sectors0 % 18 != 0 ? "invalid" : ""); - uint64_t size = io_generic_size(io); - for (int i = 0; formats[i].form_factor; i++) { + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("ddos: error getting image size\n"); + return -1; + } + + for (int i = 0; formats[i].form_factor; i++) + { const format &f = formats[i]; if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; - if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) { + if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) + { if (f.head_count == 2) { // read sector count from side 2 catalogue - io_generic_read(io, cat, (uint64_t)compute_track_size(f) * f.track_count + 0x1000, 8); // sequential + io.read_at((uint64_t)compute_track_size(f) * f.track_count + 0x1000, cat, 8, actual); // sequential sectors2 = (cat[1] << 8) + cat[2]; LOG_FORMATS("ddos: sector count 2: %d %s\n", sectors2, sectors2 % 18 != 0 ? "invalid" : ""); } @@ -311,12 +343,13 @@ int opus_ddos_format::find_size(io_generic *io, uint32_t form_factor, const std: return -1; } -int opus_ddos_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int opus_ddos_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); if (type != -1) return 90; + return 0; } @@ -369,25 +402,33 @@ const char *acorn_adfs_old_format::extensions() const return "adf,ads,adm,adl"; } -int acorn_adfs_old_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_adfs_old_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t map[3]; uint32_t sectors; uint8_t oldmap[4]; // read sector count from free space map - io_generic_read(io, map, 0xfc, 3); + io.read_at(0xfc, map, 3, actual); sectors = map[0] + (map[1] << 8) + (map[2] << 16); LOG_FORMATS("adfs_o: sector count %d %s\n", sectors, sectors % 16 != 0 ? "invalid" : ""); // read map identifier - io_generic_read(io, oldmap, 0x201, 4); + io.read_at(0x201, oldmap, 4, actual); LOG_FORMATS("adfs_o: map identifier %s %s\n", oldmap, memcmp(oldmap, "Hugo", 4) != 0 ? "invalid" : ""); - uint64_t size = io_generic_size(io); - for(int i=0; formats[i].form_factor; i++) { + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("adfs_o: error getting image size\n"); + return -1; + } + + for (int i=0; formats[i].form_factor; i++) + { const format &f = formats[i]; - if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) + if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; // valid images will have map identifier 'Hugo' and sector counts adfs-s = 0x280; adfs-m = 0x500; adfs-l = 0xa00; adfs-dos = 0xaa0; though many adfs-s images are incorrect @@ -399,12 +440,13 @@ int acorn_adfs_old_format::find_size(io_generic *io, uint32_t form_factor, const return -1; } -int acorn_adfs_old_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_adfs_old_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); if(type != -1) return 100; + return 0; } @@ -465,43 +507,50 @@ const char *acorn_adfs_new_format::extensions() const return "adf"; } -int acorn_adfs_new_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_adfs_new_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t dform[4]; uint8_t eform[4]; // read map identifiers for D and E formats - io_generic_read(io, dform, 0x401, 4); + io.read_at(0x401, dform, 4, actual); LOG_FORMATS("adfs_n: map identifier (D format) %s %s\n", dform, (memcmp(dform, "Hugo", 4) != 0 && memcmp(dform, "Nick", 4) != 0) ? "invalid" : ""); - io_generic_read(io, eform, 0x801, 4); + io.read_at(0x801, eform, 4, actual); LOG_FORMATS("adfs_n: map identifier (E format) %s %s\n", eform, memcmp(eform, "Nick", 4) != 0 ? "invalid" : ""); - uint64_t size = io_generic_size(io); - for (int i = 0; formats[i].form_factor; i++) { + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("adfs_n: error getting image size\n"); + return -1; + } + + for (int i = 0; formats[i].form_factor; i++) + { const format &f = formats[i]; if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; // no further checks for 1600K images - if ((size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && size == 0x190000) { + if ((size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && size == 0x190000) return i; - } // valid 800K images will have map identifier Nick, Arthur D format still use Hugo - if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (memcmp(dform, "Hugo", 4) == 0 || memcmp(dform, "Nick", 4) == 0 || memcmp(eform, "Nick", 4) == 0)) { + if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (memcmp(dform, "Hugo", 4) == 0 || memcmp(dform, "Nick", 4) == 0 || memcmp(eform, "Nick", 4) == 0)) return i; - } } LOG_FORMATS("adfs_n: no match\n"); return -1; } -int acorn_adfs_new_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_adfs_new_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); if (type != -1) return 100; + return 0; } @@ -546,33 +595,43 @@ const char *acorn_dos_format::extensions() const return "img"; } -int acorn_dos_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_dos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint8_t type; + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("dos: error getting image size\n"); + return -1; + } - uint64_t size = io_generic_size(io); - for(int i=0; formats[i].form_factor; i++) { + for (int i=0; formats[i].form_factor; i++) + { const format &f = formats[i]; - if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) + if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) continue; - if (size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) { + if (size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) + { // read media type ID from FAT - Acorn DOS = 0xfd - io_generic_read(io, &type, 0, 1); + size_t actual; + uint8_t type; + io.read_at(0, &type, 1, actual); LOG_FORMATS("dos: 800k media type id %02X %s\n", type, type != 0xfd ? "invalid" : ""); - if (type == 0xfd) return i; + if (type == 0xfd) + return i; } } LOG_FORMATS("dos: no match\n"); return -1; } -int acorn_dos_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int acorn_dos_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); - if(type != -1) + if (type != -1) return 90; + return 0; } @@ -618,19 +677,28 @@ bool opus_ddcpm_format::supports_save() const return false; } -int opus_ddcpm_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int opus_ddcpm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t h[8]; - io_generic_read(io, h, 0, 8); + io.read_at(0, h, 8, actual); + + uint64_t size; + if (io.length(size)) + { + LOG_FORMATS("ddcpm: error getting image size\n"); + return -1; + } - if (io_generic_size(io) == 819200 && memcmp(h, "Slogger ", 8) == 0) + if (size == 819200 && memcmp(h, "Slogger ", 8) == 0) return 100; + LOG_FORMATS("ddcpm: no match\n"); return 0; } -bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool opus_ddcpm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { // Double density discs formatted with DDCPM : // @@ -644,19 +712,21 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, const std::ve // Sector skew of 1 // Sector interleave of 2 // - int spt, bps; - - for (int head = 0; head < 2; head++) { - for (int track = 0; track < 80; track++) { - bool mfm = track > 2 || head; - bps = mfm ? 512 : 256; - spt = 10; + for (int head = 0; head < 2; head++) + { + for (int track = 0; track < 80; track++) + { + bool const mfm = track > 2 || head; + int const bps = mfm ? 512 : 256; + int const spt = 10; desc_pc_sector sects[10]; uint8_t sectdata[10*512]; - io_generic_read(io, sectdata, head * 80 * spt * 512 + track * spt * 512, spt * 512); + size_t actual; + io.read_at(head * 80 * spt * 512 + track * spt * 512, sectdata, spt * 512, actual); - for (int i = 0; i < spt; i++) { + for (int i = 0; i < spt; i++) + { sects[i].track = track; sects[i].head = head; sects[i].sector = i; @@ -677,7 +747,7 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, const std::ve return true; } -bool opus_ddcpm_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool opus_ddcpm_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/acorn_dsk.h b/src/lib/formats/acorn_dsk.h index 1428212cfaa..de07e8b9fed 100644 --- a/src/lib/formats/acorn_dsk.h +++ b/src/lib/formats/acorn_dsk.h @@ -20,8 +20,8 @@ class acorn_ssd_format : public wd177x_format public: acorn_ssd_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -36,8 +36,8 @@ class acorn_dsd_format : public wd177x_format public: acorn_dsd_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -52,8 +52,8 @@ class opus_ddos_format : public wd177x_format public: opus_ddos_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -68,8 +68,8 @@ class acorn_adfs_old_format : public wd177x_format public: acorn_adfs_old_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -84,8 +84,8 @@ class acorn_adfs_new_format : public wd177x_format public: acorn_adfs_new_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -100,8 +100,8 @@ class acorn_dos_format : public wd177x_format public: acorn_dos_format(); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; @@ -116,9 +116,9 @@ class opus_ddcpm_format : public floppy_image_format_t public: opus_ddcpm_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/afs_dsk.cpp b/src/lib/formats/afs_dsk.cpp index d6b275240de..000daf62df7 100644 --- a/src/lib/formats/afs_dsk.cpp +++ b/src/lib/formats/afs_dsk.cpp @@ -30,12 +30,13 @@ const char *afs_format::extensions() const return "adl,img"; } -int afs_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int afs_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); if (type != -1) return 50; + return 0; } diff --git a/src/lib/formats/afs_dsk.h b/src/lib/formats/afs_dsk.h index 1a15e54d90d..f56b2dcb1f4 100644 --- a/src/lib/formats/afs_dsk.h +++ b/src/lib/formats/afs_dsk.h @@ -20,7 +20,7 @@ class afs_format : public wd177x_format public: afs_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/aim_dsk.cpp b/src/lib/formats/aim_dsk.cpp index 489ec1752e4..6ad49b22969 100644 --- a/src/lib/formats/aim_dsk.cpp +++ b/src/lib/formats/aim_dsk.cpp @@ -12,10 +12,10 @@ *********************************************************************/ -#include <cassert> - #include "aim_dsk.h" +#include "ioprocs.h" + aim_format::aim_format() { @@ -40,18 +40,20 @@ const char *aim_format::extensions() const } -int aim_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int aim_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - if (io_generic_size(io) == 2068480) - { + uint64_t size; + if (io.length(size)) + return 0; + + if (size == 2068480) return 100; - } return 0; } -bool aim_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool aim_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { image->set_variant(floppy_image::DSQD); @@ -70,7 +72,8 @@ bool aim_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui bool header = false; // Read track - io_generic_read(io, &track_data[0], ( heads * track + head ) * track_size, track_size); + size_t actual; + io.read_at((heads * track + head) * track_size, &track_data[0], track_size, actual); // Find first sector header or index mark for (int offset = 0; offset < track_size; offset += 2) diff --git a/src/lib/formats/aim_dsk.h b/src/lib/formats/aim_dsk.h index c4737efc7e6..560943be30c 100644 --- a/src/lib/formats/aim_dsk.h +++ b/src/lib/formats/aim_dsk.h @@ -7,9 +7,10 @@ AIM disk images *********************************************************************/ +#ifndef MAME_FORMATS_AIM_DSK_H +#define MAME_FORMATS_AIM_DSK_H -#ifndef AIM_DSK_H -#define AIM_DSK_H +#pragma once #include "flopimg.h" @@ -20,8 +21,8 @@ class aim_format : public floppy_image_format_t public: aim_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -31,4 +32,4 @@ public: extern const floppy_format_type FLOPPY_AIM_FORMAT; -#endif /* AIM_DSK_H */ +#endif // MAME_FORMATS_AIM_DSK_H diff --git a/src/lib/formats/ami_dsk.cpp b/src/lib/formats/ami_dsk.cpp index 5973bc69dab..eb96b01377d 100644 --- a/src/lib/formats/ami_dsk.cpp +++ b/src/lib/formats/ami_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/ami_dsk.h" +#include "ioprocs.h" + + adf_format::adf_format() : floppy_image_format_t() { } @@ -36,59 +37,61 @@ bool adf_format::supports_save() const return true; } -int adf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int adf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; + if ((size == 901120) || (size == 912384) || (size == 1802240)) - { return 50; - } + return 0; } -bool adf_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool adf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { desc_s sectors[22]; uint8_t sectdata[512*22]; bool is_hd = false; int tracks = 80; - for(int i=0; i<22; i++) { + for (int i=0; i<22; i++) { sectors[i].data = sectdata + 512*i; sectors[i].size = 512; sectors[i].sector_id = i; } - uint64_t size = io_generic_size(io); - if(size == 901120) - { + uint64_t size; + if (io.length(size)) + return false; + + if (size == 901120) { is_hd = false; tracks = 80; - } - else if (size == 912384) - { + } else if (size == 912384) { is_hd = false; tracks = 81; - } - else - { + } else { is_hd = true; tracks = 80; } if (!is_hd) { image->set_variant(floppy_image::DSDD); - for(int track=0; track < tracks; track++) { - for(int side=0; side < 2; side++) { - io_generic_read(io, sectdata, (track*2 + side)*512*11, 512*11); + for (int track=0; track < tracks; track++) { + for (int side=0; side < 2; side++) { + size_t actual; + io.read_at((track*2 + side)*512*11, sectdata, 512*11, actual); generate_track(amiga_11, track, side, sectors, 11, 100000, image); } } } else { image->set_variant(floppy_image::DSHD); - for(int track=0; track < tracks; track++) { - for(int side=0; side < 2; side++) { - io_generic_read(io, sectdata, (track*2 + side)*512*22, 512*22); + for (int track=0; track < tracks; track++) { + for (int side=0; side < 2; side++) { + size_t actual; + io.read_at((track*2 + side)*512*22, sectdata, 512*22, actual); generate_track(amiga_22, track, side, sectors, 22, 200000, image); } } @@ -100,11 +103,11 @@ bool adf_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui uint32_t adf_format::g32(const std::vector<bool> &trackbuf, uint32_t pos) { uint32_t res = 0; - for(int i=0; i != 32; i++) { - if(trackbuf[pos]) + for (int i=0; i != 32; i++) { + if (trackbuf[pos]) res |= 0x80000000 >> i; - pos ++; - if(pos == trackbuf.size()) + pos++; + if (pos == trackbuf.size()) pos = 0; } return res; @@ -113,34 +116,34 @@ uint32_t adf_format::g32(const std::vector<bool> &trackbuf, uint32_t pos) uint32_t adf_format::checksum(const std::vector<bool> &trackbuf, uint32_t pos, int long_count) { uint32_t check = 0; - for(int i=0; i<long_count; i++) + for (int i=0; i<long_count; i++) check ^= g32(trackbuf, pos+32*i); return check & 0x55555555; } -bool adf_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool adf_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t sectdata[512*22]; - bool hd = image->get_variant() == floppy_image::DSHD; + bool const hd = image->get_variant() == floppy_image::DSHD; - int data_track_size = hd ? 512*22 : 512*11; + int const data_track_size = hd ? 512*22 : 512*11; - for(int track=0; track < 80; track++) { - for(int side=0; side < 2; side++) { + for (int track=0; track < 80; track++) { + for (int side=0; side < 2; side++) { auto trackbuf = generate_bitstream_from_track(track, side, hd ? 1000 : 2000, image); - for(uint32_t i=0; i<trackbuf.size(); i++) - if(g32(trackbuf, i) == 0x44894489 && + for (uint32_t i=0; i<trackbuf.size(); i++) + if (g32(trackbuf, i) == 0x44894489 && (g32(trackbuf, i+384) & 0x55555555) == checksum(trackbuf, i+32, 10) && (g32(trackbuf, i+448) & 0x55555555) == checksum(trackbuf, i+480, 256)) { uint32_t head = ((g32(trackbuf, i+32) & 0x55555555) << 1) | (g32(trackbuf, i+64) & 0x55555555); int sect = (head >> 8) & 0xff; - if(sect > (hd ? 22 : 11)) + if (sect > (hd ? 22 : 11)) continue; uint8_t *dest = sectdata + 512*sect; - for(int j=0; j<128; j++) { + for (int j=0; j<128; j++) { uint32_t val = ((g32(trackbuf, i+480+32*j) & 0x55555555) << 1) | (g32(trackbuf, i+4576+32*j) & 0x55555555); *dest++ = val >> 24; *dest++ = val >> 16; @@ -148,7 +151,8 @@ bool adf_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo *dest++ = val; } - io_generic_write(io, sectdata, (track*2 + side)*data_track_size, data_track_size); + size_t actual; + io.write_at((track*2 + side) * data_track_size, sectdata, data_track_size, actual); } } } diff --git a/src/lib/formats/ami_dsk.h b/src/lib/formats/ami_dsk.h index d25fd45a210..595beb1bcd3 100644 --- a/src/lib/formats/ami_dsk.h +++ b/src/lib/formats/ami_dsk.h @@ -19,9 +19,9 @@ class adf_format : public floppy_image_format_t public: adf_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp index 50b071d6432..8adc13d69d3 100644 --- a/src/lib/formats/ap2_dsk.cpp +++ b/src/lib/formats/ap2_dsk.cpp @@ -8,13 +8,15 @@ *********************************************************************/ -#include <cstdlib> -#include <cstring> -#include <cassert> - #include "ap2_dsk.h" #include "basicdsk.h" +#include "ioprocs.h" + +#include <cassert> +#include <cstdlib> +#include <cstring> + #define APPLE2_IMAGE_DO 0 #define APPLE2_IMAGE_PO 1 @@ -559,9 +561,12 @@ bool a2_16sect_format::supports_save() const return true; } -int a2_16sect_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int a2_16sect_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; + //uint32_t expected_size = 35 * 16 * 256; uint32_t expected_size = APPLE2_TRACK_COUNT * 16 * 256; @@ -574,9 +579,11 @@ int a2_16sect_format::identify(io_generic *io, uint32_t form_factor, const std:: return 0; } -bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_16sect_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); @@ -595,7 +602,8 @@ bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, const std::vec static const unsigned char cpm22_block1[8] = { 0xa2, 0x55, 0xa9, 0x00, 0x9d, 0x00, 0x0d, 0xca }; static const unsigned char subnod_block1[8] = { 0x63, 0xaa, 0xf0, 0x76, 0x8d, 0x63, 0xaa, 0x8e }; - io_generic_read(io, sector_data, fpos, 256*16); + size_t actual; + io.read_at(fpos, sector_data, 256*16, actual); if (track == 0 && fpos == 0) { @@ -740,7 +748,7 @@ void a2_16sect_format::update_chk(const uint8_t *data, int size, uint32_t &chk) //#define VERBOSE_SAVE -bool a2_16sect_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_16sect_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int g_tracks, g_heads; int visualgrid[16][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below @@ -938,8 +946,9 @@ bool a2_16sect_format::save(io_generic *io, const std::vector<uint32_t> &variant } for(int i=0; i<nsect; i++) { //if(nsect>0) printf("t%d,", track); - uint8_t *data = sectdata + (256)*i; - io_generic_write(io, data, pos_data, 256); + uint8_t const *const data = sectdata + (256)*i; + size_t actual; + io.write_at(pos_data, data, 256, actual); pos_data += 256; } //printf("\n"); @@ -952,11 +961,11 @@ bool a2_16sect_format::save(io_generic *io, const std::vector<uint32_t> &variant for (int i = 0; i < 16; i++) { if (visualgrid[i][j] == NOTFOUND) printf("-NF- "); else { - if (visualgrid[i][j] & ADDRFOUND) printf("a"); else printf(" "); - if (visualgrid[i][j] & ADDRGOOD) printf("A"); else printf(" "); - if (visualgrid[i][j] & DATAFOUND) printf("d"); else printf(" "); - if (visualgrid[i][j] & DATAGOOD) { printf("D"); total_good++; } else printf(" "); - if (visualgrid[i][j] & DATAPOST) printf("."); else printf(" "); + if (visualgrid[i][j] & ADDRFOUND) printf("a"); else printf(" "); + if (visualgrid[i][j] & ADDRGOOD) printf("A"); else printf(" "); + if (visualgrid[i][j] & DATAFOUND) printf("d"); else printf(" "); + if (visualgrid[i][j] & DATAGOOD) { printf("D"); total_good++; } else printf(" "); + if (visualgrid[i][j] & DATAPOST) printf("."); else printf(" "); } } printf("\n"); @@ -1019,14 +1028,16 @@ bool a2_rwts18_format::supports_save() const return true; } -int a2_rwts18_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int a2_rwts18_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); - uint32_t expected_size = APPLE2_TRACK_COUNT * 16 * 256; + uint64_t size; + if(io.length(size)) + return 0; + uint32_t const expected_size = APPLE2_TRACK_COUNT * 16 * 256; return size == expected_size; } -bool a2_rwts18_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_rwts18_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { /* TODO: rewrite me properly uint8_t sector_data[(256)*16]; @@ -1046,7 +1057,8 @@ bool a2_rwts18_format::load(io_generic *io, uint32_t form_factor, const std::vec sectors[si].size = 256; sectors[si].sector_id = si; sectors[si].sector_info = format; - io_generic_read(io, data, pos_data, 256); + size_t actual; + io.read_at(pos_data, data, 256, actual); pos_data += 256; } generate_track(mac_gcr, track, head, sectors, 16, 3104*16, image); @@ -1075,7 +1087,7 @@ void a2_rwts18_format::update_chk(const uint8_t *data, int size, uint32_t &chk) { } -bool a2_rwts18_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_rwts18_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int g_tracks, g_heads; int visualgrid[18][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below @@ -1266,8 +1278,9 @@ bool a2_rwts18_format::save(io_generic *io, const std::vector<uint32_t> &variant } for(int i=0; i<nsect; i++) { //if(nsect>0) printf("t%d,", track); - uint8_t *data = sectdata + (256)*i; - io_generic_write(io, data, pos_data, 256); + uint8_t const *const data = sectdata + (256)*i; + size_t actual; + io.write_at(pos_data, data, 256, actual); pos_data += 256; } @@ -1447,8 +1460,9 @@ bool a2_rwts18_format::save(io_generic *io, const std::vector<uint32_t> &variant } for(int i=0; i<nsect; i++) { //if(nsect>0) printf("t%d,", track); - uint8_t *data = sectdata + (256)*i; - io_generic_write(io, data, pos_data, 256); + uint8_t const *const data = sectdata + (256)*i; + size_t actual; + io.write_at(pos_data, data, 256, actual); pos_data += 256; } //printf("\n"); @@ -1500,9 +1514,12 @@ bool a2_edd_format::supports_save() const return false; } -int a2_edd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int a2_edd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - return ((io_generic_size(io) == 2244608) || (io_generic_size(io) == 2310144)) ? 50 : 0; + uint64_t size; + if (io.length(size)) + return 0; + return ((size == 2244608) || (size == 2310144)) ? 50 : 0; } uint8_t a2_edd_format::pick(const uint8_t *data, int pos) @@ -1510,23 +1527,20 @@ uint8_t a2_edd_format::pick(const uint8_t *data, int pos) return ((data[pos>>3] << 8) | data[(pos>>3)+1]) >> (8-(pos & 7)); } -bool a2_edd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_edd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint8_t *img; uint8_t nibble[16384], stream[16384]; int npos[16384]; - img = (uint8_t *) malloc(2244608); - + std::unique_ptr<uint8_t []> img(new (std::nothrow) uint8_t[2244608]); if (!img) - { return false; - } - io_generic_read(io, img, 0, 2244608); + size_t actual; + io.read_at(0, img.get(), 2244608, actual); for(int i=0; i<137; i++) { - const uint8_t *trk = img + 16384*i; + uint8_t const *const trk = &img[16384*i]; int pos = 0; int wpos = 0; while(pos < 16383*8) { @@ -1590,7 +1604,7 @@ bool a2_edd_format::load(io_generic *io, uint32_t form_factor, const std::vector generate_track_from_bitstream(i >> 2, 0, stream, len, image, i & 3); image->set_write_splice_position(i >> 2, 0, uint32_t(uint64_t(200'000'000)*splice/len), i & 3); } - free(img); + img.reset(); image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); @@ -1627,26 +1641,31 @@ bool a2_woz_format::supports_save() const const uint8_t a2_woz_format::signature[8] = { 0x57, 0x4f, 0x5a, 0x31, 0xff, 0x0a, 0x0d, 0x0a }; const uint8_t a2_woz_format::signature2[8] = { 0x57, 0x4f, 0x5a, 0x32, 0xff, 0x0a, 0x0d, 0x0a }; -int a2_woz_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int a2_woz_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[8]; - io_generic_read(io, header, 0, 8); + size_t actual; + io.read_at(0, header, 8, actual); if (!memcmp(header, signature, 8)) return 100; if (!memcmp(header, signature2, 8)) return 100; return 0; } -bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_woz_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - std::vector<uint8_t> img(io_generic_size(io)); - io_generic_read(io, &img[0], 0, img.size()); + uint64_t image_size; + if(io.length(image_size)) + return false; + std::vector<uint8_t> img(image_size); + size_t actual; + io.read_at(0, &img[0], img.size(), actual); // Check signature - if ((memcmp(&img[0], signature, 8)) && (memcmp(&img[0], signature2, 8))) + if((memcmp(&img[0], signature, 8)) && (memcmp(&img[0], signature2, 8))) return false; uint32_t woz_vers = 1; - if (!memcmp(&img[0], signature2, 8)) woz_vers = 2; + if(!memcmp(&img[0], signature2, 8)) woz_vers = 2; // Check integrity uint32_t crc = crc32r(&img[12], img.size() - 12); @@ -1663,7 +1682,7 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector uint32_t info_vers = r8(img, off_info + 0); - if ((info_vers != 1) && (info_vers != 2)) + if((info_vers != 1) && (info_vers != 2)) return false; bool is_35 = r8(img, off_info + 1) == 2; @@ -1721,7 +1740,7 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector return true; } -bool a2_woz_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_woz_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { std::vector<std::vector<bool>> tracks(160); bool twosided = false; @@ -1823,7 +1842,8 @@ bool a2_woz_format::save(io_generic *io, const std::vector<uint32_t> &variants, w32(data, 8, crc32r(&data[12], data.size() - 12)); - io_generic_write(io, data.data(), 0, data.size()); + size_t actual; + io.write_at(0, data.data(), data.size(), actual); return true; } @@ -1911,12 +1931,15 @@ bool a2_nib_format::supports_save() const return false; } -int a2_nib_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int a2_nib_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - const auto size = io_generic_size(io); - if (size == expected_size_35t || size == expected_size_40t) { + uint64_t size; + if (io.length(size)) + return 0; + + if (size == expected_size_35t || size == expected_size_40t) return 50; - } + return 0; } @@ -2031,18 +2054,20 @@ std::vector<uint32_t> a2_nib_format::generate_levels_from_nibbles(const std::vec return levels; } -bool a2_nib_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool a2_nib_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - auto size = io_generic_size(io); - if (size != expected_size_35t && size != expected_size_40t) { + uint64_t size; + if (io.length(size)) return false; - } + if (size != expected_size_35t && size != expected_size_40t) + return false; + const auto nr_tracks = size == expected_size_35t? 35 : 40; std::vector<uint8_t> nibbles(nibbles_per_track); for (unsigned track = 0; track < nr_tracks; ++track) { - io_generic_read(io, &nibbles[0], - track * nibbles_per_track, nibbles_per_track); + size_t actual; + io.read_at(track * nibbles_per_track, &nibbles[0], nibbles_per_track, actual); auto levels = generate_levels_from_nibbles(nibbles); generate_track_from_levels(track, 0, levels, diff --git a/src/lib/formats/ap2_dsk.h b/src/lib/formats/ap2_dsk.h index 7420d72d818..bab61cf96b8 100644 --- a/src/lib/formats/ap2_dsk.h +++ b/src/lib/formats/ap2_dsk.h @@ -41,9 +41,9 @@ class a2_16sect_format : public floppy_image_format_t public: a2_16sect_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -68,9 +68,9 @@ class a2_rwts18_format : public floppy_image_format_t public: a2_rwts18_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -92,8 +92,8 @@ class a2_edd_format : public floppy_image_format_t public: a2_edd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; virtual const char *name() const override; @@ -111,9 +111,9 @@ class a2_woz_format : public floppy_image_format_t public: a2_woz_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; virtual const char *name() const override; @@ -141,8 +141,8 @@ class a2_nib_format : public floppy_image_format_t public: a2_nib_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; virtual const char *name() const override; diff --git a/src/lib/formats/ap_dsk35.cpp b/src/lib/formats/ap_dsk35.cpp index 9819406183c..6a3fa5d742b 100644 --- a/src/lib/formats/ap_dsk35.cpp +++ b/src/lib/formats/ap_dsk35.cpp @@ -100,6 +100,8 @@ #include "ap_dsk35.h" +#include "ioprocs.h" + #include <cassert> #include <cstdio> @@ -1233,14 +1235,15 @@ bool dc42_format::supports_save() const return true; } -int dc42_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dc42_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint8_t h[0x54]; - uint64_t size = io_generic_size(io); - if(size < 0x54) + uint64_t size; + if(io.length(size) || (size < 0x54)) return 0; - io_generic_read(io, h, 0, 0x54); + uint8_t h[0x54]; + size_t actual; + io.read_at(0, h, 0x54, actual); uint32_t dsize = (h[0x40] << 24) | (h[0x41] << 16) | (h[0x42] << 8) | h[0x43]; uint32_t tsize = (h[0x44] << 24) | (h[0x45] << 16) | (h[0x46] << 8) | h[0x47]; @@ -1252,13 +1255,14 @@ int dc42_format::identify(io_generic *io, uint32_t form_factor, const std::vecto return 0; } - return size == 0x54+tsize+dsize && h[0] < 64 && h[0x52] == 1 && h[0x53] == 0 ? 100 : 0; + return (size == 0x54+tsize+dsize && h[0] < 64 && h[0x52] == 1 && h[0x53] == 0) ? 100 : 0; } -bool dc42_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dc42_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t h[0x54]; - io_generic_read(io, h, 0, 0x54); + io.read_at(0, h, 0x54, actual); int dsize = (h[0x40] << 24) | (h[0x41] << 16) | (h[0x42] << 8) | h[0x43]; int tsize = (h[0x44] << 24) | (h[0x45] << 16) | (h[0x46] << 8) | h[0x47]; @@ -1270,8 +1274,7 @@ bool dc42_format::load(io_generic *io, uint32_t form_factor, const std::vector<u return false; } - switch (dsize) - { + switch(dsize) { case 409600: // Mac 400K image->set_form_variant(floppy_image::FF_35, floppy_image::SSDD); break; @@ -1315,13 +1318,14 @@ bool dc42_format::load(io_generic *io, uint32_t form_factor, const std::vector<u sectors[si].sector = i; sectors[si].info = format; if(tsize) { - io_generic_read(io, data, pos_tag, 12); + io.read_at(pos_tag, data, 12, actual); sectors[si].tag = data; pos_tag += 12; - } else + } else { sectors[si].tag = nullptr; + } sectors[si].data = data+12; - io_generic_read(io, data+12, pos_data, 512); + io.read_at(pos_data, data+12, 512, actual); pos_data += 512; si = (si + 2) % ns; if(si == 0) @@ -1341,7 +1345,7 @@ void dc42_format::update_chk(const uint8_t *data, int size, uint32_t &chk) } } -bool dc42_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool dc42_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int g_tracks, g_heads; image->get_actual_geometry(g_tracks, g_heads); @@ -1381,8 +1385,9 @@ bool dc42_format::save(io_generic *io, const std::vector<uint32_t> &variants, fl for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - io_generic_write(io, &sdata[0], pos_tag, 12); - io_generic_write(io, &sdata[12], pos_data, 512); + size_t actual; + io.write_at(pos_tag, &sdata[0], 12, actual); + io.write_at(pos_data, &sdata[12], 512, actual); pos_tag += 12; pos_data += 512; if(track || head || i) @@ -1401,7 +1406,8 @@ bool dc42_format::save(io_generic *io, const std::vector<uint32_t> &variants, fl h[0x4e] = tchk >> 8; h[0x4f] = tchk; - io_generic_write(io, h, 0, 0x54); + size_t actual; + io.write_at(0, h, 0x54, actual); return true; } @@ -1432,26 +1438,32 @@ bool apple_gcr_format::supports_save() const return true; } -int apple_gcr_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int apple_gcr_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; + if(size == 409600 || (size == 819200 && (variants.empty() || has_variant(variants, floppy_image::DSDD)))) return 50; return 0; } -bool apple_gcr_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool apple_gcr_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; desc_gcr_sector sectors[12]; uint8_t sdata[512*12]; int pos_data = 0; uint8_t header[64]; - io_generic_read(io, header, 0, 64); + io.read_at(0, header, 64, actual); - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; int head_count = size == 409600 ? 1 : size == 819200 ? 2 : 0; image->set_form_variant(floppy_image::FF_35, head_count == 2 ? floppy_image::DSDD : floppy_image::SSDD); @@ -1461,7 +1473,7 @@ bool apple_gcr_format::load(io_generic *io, uint32_t form_factor, const std::vec for(int track=0; track < 80; track++) { for(int head=0; head < head_count; head++) { int ns = 12 - (track/16); - io_generic_read(io, sdata, pos_data, 512*ns); + io.read_at(pos_data, sdata, 512*ns, actual); pos_data += 512*ns; int si = 0; @@ -1482,7 +1494,7 @@ bool apple_gcr_format::load(io_generic *io, uint32_t form_factor, const std::vec return true; } -bool apple_gcr_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool apple_gcr_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int g_tracks, g_heads; image->get_actual_geometry(g_tracks, g_heads); @@ -1498,7 +1510,8 @@ bool apple_gcr_format::save(io_generic *io, const std::vector<uint32_t> &variant for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - io_generic_write(io, &sdata[12], pos_data, 512); + size_t actual; + io.write_at(pos_data, &sdata[12], 512, actual); pos_data += 512; } } @@ -1534,10 +1547,11 @@ bool apple_2mg_format::supports_save() const return true; } -int apple_2mg_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int apple_2mg_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t signature[4]; - io_generic_read(io, signature, 0, 4); + size_t actual; + io.read_at(0, signature, 4, actual); if (!strncmp(reinterpret_cast<char *>(signature), "2IMG", 4)) { return 100; @@ -1552,11 +1566,12 @@ int apple_2mg_format::identify(io_generic *io, uint32_t form_factor, const std:: return 0; } -bool apple_2mg_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool apple_2mg_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; desc_gcr_sector sectors[12]; uint8_t sdata[512*12], header[64]; - io_generic_read(io, header, 0, 64); + io.read_at(0, header, 64, actual); uint32_t blocks = header[0x14] | (header[0x15] << 8) | (header[0x16] << 16) | (header[0x17] << 24); uint32_t pos_data = header[0x18] | (header[0x19] << 8) | (header[0x1a] << 16) | (header[0x1b] << 24); @@ -1568,7 +1583,7 @@ bool apple_2mg_format::load(io_generic *io, uint32_t form_factor, const std::vec for(int track=0; track < 80; track++) { for(int head=0; head < 2; head++) { int ns = 12 - (track/16); - io_generic_read(io, sdata, pos_data, 512*ns); + io.read_at(pos_data, sdata, 512*ns, actual); pos_data += 512*ns; int si = 0; @@ -1589,8 +1604,10 @@ bool apple_2mg_format::load(io_generic *io, uint32_t form_factor, const std::vec return true; } -bool apple_2mg_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool apple_2mg_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; + uint8_t header[0x40]; int pos_data = 0x40; @@ -1611,7 +1628,7 @@ bool apple_2mg_format::save(io_generic *io, const std::vector<uint32_t> &variant header[0x18] = 0x40; // bytes of disk data header[0x1c] = 0x00; header[0x1d] = 0x80; header[0x1e] = 0x0c; // 0xC8000 (819200) - io_generic_write(io, header, 0, 0x40); + io.write_at(0, header, 0x40, actual); for(int track=0; track < 80; track++) { for(int head=0; head < 2; head++) { @@ -1619,7 +1636,7 @@ bool apple_2mg_format::save(io_generic *io, const std::vector<uint32_t> &variant for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - io_generic_write(io, &sdata[12], pos_data, 512); + io.write_at(pos_data, &sdata[12], 512, actual); pos_data += 512; } } diff --git a/src/lib/formats/ap_dsk35.h b/src/lib/formats/ap_dsk35.h index def1cb86856..f4a8ec7bff8 100644 --- a/src/lib/formats/ap_dsk35.h +++ b/src/lib/formats/ap_dsk35.h @@ -29,9 +29,9 @@ class dc42_format : public floppy_image_format_t public: dc42_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -49,9 +49,9 @@ class apple_gcr_format : public floppy_image_format_t public: apple_gcr_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -66,9 +66,9 @@ class apple_2mg_format : public floppy_image_format_t public: apple_2mg_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/apd_dsk.cpp b/src/lib/formats/apd_dsk.cpp index 45d385a0800..f882d90fe23 100644 --- a/src/lib/formats/apd_dsk.cpp +++ b/src/lib/formats/apd_dsk.cpp @@ -60,9 +60,13 @@ *********************************************************************/ -#include <zlib.h> #include "formats/apd_dsk.h" +#include "ioprocs.h" + +#include <zlib.h> + + static const uint8_t APD_HEADER[8] = { 'A', 'P', 'D', 'X', '0', '0', '0', '1' }; static const uint8_t GZ_HEADER[2] = { 0x1f, 0x8b }; @@ -85,11 +89,15 @@ const char *apd_format::extensions() const return "apd"; } -int apd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int apd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; + std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); int err; std::vector<uint8_t> gz_ptr(8); @@ -123,11 +131,15 @@ int apd_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool apd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool apd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; + std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); int err; std::vector<uint8_t> gz_ptr; diff --git a/src/lib/formats/apd_dsk.h b/src/lib/formats/apd_dsk.h index bc551973c4a..8c3ac6f0d42 100644 --- a/src/lib/formats/apd_dsk.h +++ b/src/lib/formats/apd_dsk.h @@ -23,8 +23,8 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; }; diff --git a/src/lib/formats/apollo_dsk.cpp b/src/lib/formats/apollo_dsk.cpp index 75c31cfe7f8..a1159ac68c8 100644 --- a/src/lib/formats/apollo_dsk.cpp +++ b/src/lib/formats/apollo_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/apollo_dsk.h" +#include "ioprocs.h" + + apollo_format::apollo_format() : upd765_format(formats) { } @@ -46,10 +47,13 @@ const apollo_format::format apollo_format::formats[] = { const floppy_format_type FLOPPY_APOLLO_FORMAT = &floppy_image_format_creator<apollo_format>; -int apollo_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int apollo_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); - uint32_t expected_size = 77*2*8*1024; + uint64_t size; + if (io.length(size)) + return 0; + + constexpr uint32_t expected_size = 77*2*8*1024; return ((size == expected_size) || (size == 0)) ? 1 : 0; } diff --git a/src/lib/formats/apollo_dsk.h b/src/lib/formats/apollo_dsk.h index 6376c77b067..1c2c6d81030 100644 --- a/src/lib/formats/apollo_dsk.h +++ b/src/lib/formats/apollo_dsk.h @@ -19,7 +19,7 @@ class apollo_format : public upd765_format public: apollo_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; diff --git a/src/lib/formats/apridisk.cpp b/src/lib/formats/apridisk.cpp index 388d358f6f8..1560c199149 100644 --- a/src/lib/formats/apridisk.cpp +++ b/src/lib/formats/apridisk.cpp @@ -12,6 +12,8 @@ #include "imageutl.h" +#include "ioprocs.h" + apridisk_format::apridisk_format() { @@ -32,10 +34,11 @@ const char *apridisk_format::extensions() const return "dsk"; } -int apridisk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int apridisk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[APR_HEADER_SIZE]; - io_generic_read(io, header, 0, APR_HEADER_SIZE); + size_t actual; + io.read_at(0, header, APR_HEADER_SIZE, actual); const char magic[] = "ACT Apricot disk image\x1a\x04"; @@ -45,21 +48,26 @@ int apridisk_format::identify(io_generic *io, uint32_t form_factor, const std::v return 0; } -bool apridisk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool apridisk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { desc_pc_sector sectors[80][2][18]; std::unique_ptr<uint8_t []> sector_data(new uint8_t [MAX_SECTORS * SECTOR_SIZE]); uint8_t *data_ptr = sector_data.get(); int track_count = 0, head_count = 0, sector_count = 0; - uint64_t file_size = io_generic_size(io); + uint64_t file_size; + if (io.length(file_size)) + return false; + uint64_t file_offset = APR_HEADER_SIZE; while (file_offset < file_size) { + size_t actual; + // read sector header uint8_t sector_header[16]; - io_generic_read(io, sector_header, file_offset, 16); + io.read_at(file_offset, sector_header, 16, actual); uint32_t type = pick_integer_le(§or_header, 0, 4); uint16_t compression = pick_integer_le(§or_header, 4, 2); @@ -94,7 +102,7 @@ bool apridisk_format::load(io_generic *io, uint32_t form_factor, const std::vect case APR_COMPRESSED: { uint8_t comp[3]; - io_generic_read(io, comp, file_offset, 3); + io.read_at(file_offset, comp, 3, actual); uint16_t length = pick_integer_le(comp, 0, 2); if (length != SECTOR_SIZE) @@ -108,7 +116,7 @@ bool apridisk_format::load(io_generic *io, uint32_t form_factor, const std::vect break; case APR_UNCOMPRESSED: - io_generic_read(io, data_ptr, file_offset, SECTOR_SIZE); + io.read_at(file_offset, data_ptr, SECTOR_SIZE, actual); break; default: @@ -140,7 +148,7 @@ bool apridisk_format::load(io_generic *io, uint32_t form_factor, const std::vect return true; } -bool apridisk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool apridisk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/apridisk.h b/src/lib/formats/apridisk.h index 3e751f8d6ec..5cc8a1403fb 100644 --- a/src/lib/formats/apridisk.h +++ b/src/lib/formats/apridisk.h @@ -23,9 +23,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; private: diff --git a/src/lib/formats/cassimg.cpp b/src/lib/formats/cassimg.cpp index cf5812c67c1..2fab4a1ec8b 100644 --- a/src/lib/formats/cassimg.cpp +++ b/src/lib/formats/cassimg.cpp @@ -199,12 +199,15 @@ cassette_image::error cassette_image::lookup_sample(int channel, size_t sample, -cassette_image::cassette_image(const Format *format, void *file, const io_procs *procs, int flags) +cassette_image::cassette_image(const Format *format, util::random_read_write::ptr &&io, int flags) : + m_format(format), + m_io(std::move(io)), + m_channels(0), + m_flags(flags), + m_sample_frequency(0), + m_blocks(), + m_sample_count(0) { - m_format = format; - m_io.file = file; - m_io.procs = procs; - m_flags = flags; } @@ -217,17 +220,24 @@ cassette_image::~cassette_image() -cassette_image::error cassette_image::open(void *file, const io_procs *procs, - const Format *format, int flags, ptr &outcassette) +cassette_image::error cassette_image::open( + util::random_read_write::ptr &&io, + const Format *format, + int flags, + ptr &outcassette) { const Format *const formats[2] = { format, nullptr }; - return open_choices(file, procs, {}, formats, flags, outcassette); + return open_choices(std::move(io), { }, formats, flags, outcassette); } -cassette_image::error cassette_image::open_choices(void *file, const io_procs *procs, const std::string &extension, - const Format *const *formats, int flags, ptr &outcassette) +cassette_image::error cassette_image::open_choices( + util::random_read_write::ptr &&io, + const std::string &extension, + const Format *const *formats, + int flags, + ptr &outcassette) { // if not specified, use the dummy arguments if (!formats) @@ -235,7 +245,7 @@ cassette_image::error cassette_image::open_choices(void *file, const io_procs *p // create the cassette object ptr cassette; - try { cassette.reset(new cassette_image(nullptr, file, procs, flags)); } + try { cassette.reset(new cassette_image(nullptr, std::move(io), flags)); } catch (std::bad_alloc const &) { return error::OUT_OF_MEMORY; } // identify the image @@ -275,8 +285,12 @@ cassette_image::error cassette_image::open_choices(void *file, const io_procs *p -cassette_image::error cassette_image::create(void *file, const io_procs *procs, const Format *format, - const Options *opts, int flags, ptr &outcassette) +cassette_image::error cassette_image::create( + util::random_read_write::ptr &&io, + const Format *format, + const Options *opts, + int flags, + ptr &outcassette) { static const Options default_options = { 1, 16, 44100 }; @@ -294,7 +308,7 @@ cassette_image::error cassette_image::create(void *file, const io_procs *procs, // create the cassette object ptr cassette; - try { cassette.reset(new cassette_image(format, file, procs, flags)); } + try { cassette.reset(new cassette_image(format, std::move(io), flags)); } catch (std::bad_alloc const &) { return error::OUT_OF_MEMORY; } // read the options @@ -334,13 +348,13 @@ cassette_image::Info cassette_image::get_info() const -void cassette_image::change(void *file, const io_procs *procs, const Format *format, int flags) +void cassette_image::change(util::random_read_write::ptr &&io, const Format *format, int flags) { - if ((flags & FLAG_READONLY) == 0) + if (!(flags & FLAG_READONLY)) flags |= CASSETTE_FLAG_DIRTY; - m_io.file = file; - m_io.procs = procs; + m_format = format; + m_io = std::move(io); m_flags = flags; } @@ -352,7 +366,8 @@ void cassette_image::change(void *file, const io_procs *procs, const Format *for void cassette_image::image_read(void *buffer, uint64_t offset, size_t length) { - io_generic_read(&m_io, buffer, offset, length); + size_t actual; + m_io->read_at(offset, buffer, length, actual); } @@ -360,7 +375,7 @@ void cassette_image::image_read(void *buffer, uint64_t offset, size_t length) uint8_t cassette_image::image_read_byte(uint64_t offset) { uint8_t data; - io_generic_read(&m_io, &data, offset, 1); + image_read(&data, offset, 1); return data; } @@ -368,14 +383,17 @@ uint8_t cassette_image::image_read_byte(uint64_t offset) void cassette_image::image_write(const void *buffer, uint64_t offset, size_t length) { - io_generic_write(&m_io, buffer, offset, length); + size_t actual; + m_io->write_at(offset, buffer, length, actual); } uint64_t cassette_image::image_size() { - return io_generic_size(&m_io); + uint64_t size = 0; + m_io->length(size); + return size; } @@ -900,20 +918,19 @@ done: void cassette_image::dump(const char *filename) { - FILE *f = fopen(filename, "wb"); - if (!f) + util::random_read_write::ptr saved_io = util::stdio_read_write(fopen(filename, "wb"), 0); + if (!saved_io) return; - io_generic saved_io = m_io; - const Format *saved_format = m_format; + Format const *const saved_format = m_format; - m_io.file = f; - m_io.procs = &stdio_ioprocs_noclose; + using std::swap; + + swap(m_io, saved_io); m_format = &wavfile_format; + perform_save(); - m_io = saved_io; + swap(m_io, saved_io); m_format = saved_format; - - fclose(f); } diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h index 3a59870571a..765b860b659 100644 --- a/src/lib/formats/cassimg.h +++ b/src/lib/formats/cassimg.h @@ -185,14 +185,14 @@ public: void dump(const char *filename); error save(); - void change(void *file, const io_procs *procs, const Format *format, int flags); + void change(util::random_read_write::ptr &&io, const Format *format, int flags); Info get_info() const; - static error open(void *file, const io_procs *procs, + static error open(util::random_read_write::ptr &&io, const Format *format, int flags, ptr &outcassette); - static error open_choices(void *file, const io_procs *procs, const std::string &extension, + static error open_choices(util::random_read_write::ptr &&io, const std::string &extension, const Format *const *formats, int flags, ptr &outcassette); - static error create(void *file, const io_procs *procs, const cassette_image::Format *format, + static error create(util::random_read_write::ptr &&io, const cassette_image::Format *format, const cassette_image::Options *opts, int flags, ptr &outcassette); // builtin formats @@ -201,7 +201,7 @@ public: private: struct manipulation_ranges; - cassette_image(const Format *format, void *file, const io_procs *procs, int flags); + cassette_image(const Format *format, util::random_read_write::ptr &&io, int flags); cassette_image(const cassette_image &) = delete; cassette_image(cassette_image &&) = delete; cassette_image &operator=(const cassette_image &) = delete; @@ -212,15 +212,15 @@ private: error compute_manipulation_ranges(int channel, double time_index, double sample_period, manipulation_ranges &ranges) const; error lookup_sample(int channel, size_t sample, int32_t *&ptr); - const Format *m_format = nullptr; - io_generic m_io; + const Format *m_format; + util::random_read_write::ptr m_io; - int m_channels = 0; - int m_flags = 0; - uint32_t m_sample_frequency = 0; + int m_channels; + int m_flags; + uint32_t m_sample_frequency; std::vector<std::unique_ptr<int32_t []> > m_blocks; - size_t m_sample_count = 0; + size_t m_sample_count; }; /* macros for specifying format lists */ diff --git a/src/lib/formats/ccvf_dsk.cpp b/src/lib/formats/ccvf_dsk.cpp index bba52d3922a..6ed0c14038a 100644 --- a/src/lib/formats/ccvf_dsk.cpp +++ b/src/lib/formats/ccvf_dsk.cpp @@ -11,6 +11,7 @@ #include "formats/ccvf_dsk.h" #include "coretmpl.h" // BIT +#include "ioprocs.h" ccvf_format::ccvf_format() @@ -46,12 +47,12 @@ const ccvf_format::format ccvf_format::file_formats[] = { {} }; -int ccvf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ccvf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { char h[36]; - - io_generic_read(io, h, 0, 36); - if(!memcmp(h, "Compucolor Virtual Floppy Disk Image", 36)) + size_t actual; + io.read_at(0, h, 36, actual); + if (!memcmp(h, "Compucolor Virtual Floppy Disk Image", 36)) return 100; return 0; @@ -87,13 +88,17 @@ floppy_image_format_t::desc_e* ccvf_format::get_desc_8n1(const format &f, int &c return desc; } -bool ccvf_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool ccvf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { const format &f = formats[0]; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; + std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); std::string ccvf = std::string((const char *)&img[0], size); std::vector<uint8_t> bytes(78720); diff --git a/src/lib/formats/ccvf_dsk.h b/src/lib/formats/ccvf_dsk.h index 5895a882550..92f04e03ddd 100644 --- a/src/lib/formats/ccvf_dsk.h +++ b/src/lib/formats/ccvf_dsk.h @@ -39,8 +39,8 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; protected: diff --git a/src/lib/formats/concept_dsk.cpp b/src/lib/formats/concept_dsk.cpp index 67c8562e1c3..7f5edce3363 100644 --- a/src/lib/formats/concept_dsk.cpp +++ b/src/lib/formats/concept_dsk.cpp @@ -10,11 +10,11 @@ *********************************************************************/ -#include <cassert> - -#include "flopimg.h" #include "formats/concept_dsk.h" +#include "ioprocs.h" + + /* 9 sectors / track, 512 bytes per sector */ const floppy_image_format_t::desc_e cc525dsdd_format::cc_9_desc[] = { { MFM, 0x4e, 80 }, @@ -72,50 +72,50 @@ bool cc525dsdd_format::supports_save() const return true; } -void cc525dsdd_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void cc525dsdd_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { - uint64_t size = io_generic_size(io); - track_count = 77; head_count = 2; sector_count = 9; - uint32_t expected_size = 512 * track_count*head_count*sector_count; - if (size == expected_size) - { + uint32_t const expected_size = 512 * track_count*head_count*sector_count; + + uint64_t size; + if (!io.length(size) && (size == expected_size)) return; - } track_count = head_count = sector_count = 0; } -int cc525dsdd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int cc525dsdd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); - if(track_count) + if (track_count) return 50; + return 0; } -bool cc525dsdd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool cc525dsdd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); uint8_t sectdata[10*512]; desc_s sectors[10]; - for(int i=0; i<sector_count; i++) { + for (int i=0; i<sector_count; i++) { sectors[i+1].data = sectdata + 512*i; sectors[i+1].size = 512; sectors[i+1].sector_id = i+1; } int track_size = sector_count*512; - for(int track=0; track < track_count; track++) { - for(int head=0; head < head_count; head++) { - io_generic_read(io, sectdata, (track*head_count + head)*track_size, track_size); + for (int track=0; track < track_count; track++) { + for (int head=0; head < head_count; head++) { + size_t actual; + io.read_at((track*head_count + head) * track_size, sectdata, track_size, actual); generate_track(cc_9_desc, track, head, sectors, sector_count, 100000, image); } } @@ -125,28 +125,29 @@ bool cc525dsdd_format::load(io_generic *io, uint32_t form_factor, const std::vec return true; } -bool cc525dsdd_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool cc525dsdd_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); - if(track_count != 77) + if (track_count != 77) track_count = 77; // Happens for a fully unformatted floppy - if(!head_count) + if (!head_count) head_count = 2; - if(sector_count != 9) + if (sector_count != 9) sector_count = 9; uint8_t sectdata[9*512]; int track_size = sector_count*512; - for(int track=0; track < track_count; track++) { - for(int head=0; head < head_count; head++) { + for (int track=0; track < track_count; track++) { + for (int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); } } diff --git a/src/lib/formats/concept_dsk.h b/src/lib/formats/concept_dsk.h index 58d4e1c52b3..36e3f790a84 100644 --- a/src/lib/formats/concept_dsk.h +++ b/src/lib/formats/concept_dsk.h @@ -17,9 +17,9 @@ class cc525dsdd_format : public floppy_image_format_t public: cc525dsdd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -29,7 +29,7 @@ public: static const desc_e cc_9_desc[]; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; extern const floppy_format_type FLOPPY_CONCEPT_525DSDD_FORMAT; diff --git a/src/lib/formats/coupedsk.cpp b/src/lib/formats/coupedsk.cpp index 16842583855..9400cd41bb6 100644 --- a/src/lib/formats/coupedsk.cpp +++ b/src/lib/formats/coupedsk.cpp @@ -8,10 +8,10 @@ **************************************************************************/ -#include <cassert> +#include "coupedsk.h" + +#include "ioprocs.h" -#include "formats/coupedsk.h" -#include "flopimg.h" const floppy_image_format_t::desc_e mgt_format::desc_10[] = { { MFM, 0x4e, 60 }, @@ -64,9 +64,11 @@ bool mgt_format::supports_save() const return true; } -int mgt_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int mgt_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; if(/*size == 737280 || */ size == 819200) return 50; @@ -74,10 +76,12 @@ int mgt_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool mgt_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool mgt_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); - int sector_count = size == 737280 ? 9 : 10; + uint64_t size; + if(io.length(size)) + return false; + int const sector_count = (size == 737280) ? 9 : 10; uint8_t sectdata[10*512]; desc_s sectors[10]; @@ -90,7 +94,8 @@ bool mgt_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui int track_size = sector_count*512; for(int head=0; head < 2; head++) { for(int track=0; track < 80; track++) { - io_generic_read(io, sectdata, (track*2+head)*track_size, track_size); + size_t actual; + io.read_at((track*2+head)*track_size, sectdata, track_size, actual); generate_track(desc_10, track, head, sectors, sector_count+1, 100000, image); } } @@ -99,7 +104,7 @@ bool mgt_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool mgt_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool mgt_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); @@ -115,7 +120,8 @@ bool mgt_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo for(int head=0; head < 2; head++) { for(int track=0; track < 80; track++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (track*2+head)*track_size, track_size); + size_t actual; + io.write_at((track*2+head)*track_size, sectdata, track_size, actual); } } diff --git a/src/lib/formats/coupedsk.h b/src/lib/formats/coupedsk.h index 3700d3e9974..e9ef4b118ca 100644 --- a/src/lib/formats/coupedsk.h +++ b/src/lib/formats/coupedsk.h @@ -19,9 +19,9 @@ class mgt_format : public floppy_image_format_t public: mgt_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/cqm_dsk.cpp b/src/lib/formats/cqm_dsk.cpp index 5f79a4d3694..6639e50f801 100644 --- a/src/lib/formats/cqm_dsk.cpp +++ b/src/lib/formats/cqm_dsk.cpp @@ -8,9 +8,12 @@ *********************************************************************/ +#include "cqm_dsk.h" + +#include "ioprocs.h" + #include <cstring> -#include <cassert> -#include "flopimg.h" + #define CQM_HEADER_SIZE 133 @@ -231,17 +234,6 @@ FLOPPY_CONSTRUCT( cqm_dsk_construct ) - -/********************************************************************* - - formats/cqm_dsk.c - - CopyQM disk images - -*********************************************************************/ - -#include "cqm_dsk.h" - cqm_format::cqm_format() { } @@ -261,10 +253,11 @@ const char *cqm_format::extensions() const return "cqm,cqi,dsk"; } -int cqm_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int cqm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[3]; - io_generic_read(io, h, 0, 3); + size_t actual; + io.read_at(0, h, 3, actual); if (h[0] == 'C' && h[1] == 'Q' && h[2] == 0x14) return 100; @@ -272,12 +265,13 @@ int cqm_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool cqm_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool cqm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy std::vector<uint8_t> imagebuf(max_size); uint8_t header[CQM_HEADER_SIZE]; - io_generic_read(io, header, 0, CQM_HEADER_SIZE); + io.read_at(0, header, CQM_HEADER_SIZE, actual); int sector_size = (header[0x04] << 8) | header[0x03]; int sector_per_track = (header[0x11] << 8) | header[0x10]; @@ -318,9 +312,11 @@ bool cqm_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; - int cqm_size = io_generic_size(io); + uint64_t cqm_size; + if (io.length(cqm_size)) + return false; std::vector<uint8_t> cqmbuf(cqm_size); - io_generic_read(io, &cqmbuf[0], 0, cqm_size); + io.read_at(0, &cqmbuf[0], cqm_size, actual); // decode the RLE data for (int s = 0, pos = CQM_HEADER_SIZE + comment_size; pos < cqm_size; ) @@ -369,7 +365,7 @@ bool cqm_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool cqm_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool cqm_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/cqm_dsk.h b/src/lib/formats/cqm_dsk.h index 183c0b83e68..fc8376a2b85 100644 --- a/src/lib/formats/cqm_dsk.h +++ b/src/lib/formats/cqm_dsk.h @@ -19,9 +19,9 @@ class cqm_format : public floppy_image_format_t public: cqm_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/d64_dsk.cpp b/src/lib/formats/d64_dsk.cpp index 4819ecc68d2..149130f0b3c 100644 --- a/src/lib/formats/d64_dsk.cpp +++ b/src/lib/formats/d64_dsk.cpp @@ -12,6 +12,8 @@ #include "formats/d64_dsk.h" +#include "ioprocs.h" + d64_format::d64_format() { @@ -79,9 +81,12 @@ const int d64_format::speed_zone[] = 0, 0 // 41-42 }; -int d64_format::find_size(io_generic *io, uint32_t form_factor) const +int d64_format::find_size(util::random_read &io, uint32_t form_factor) const { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; + for(int i=0; formats[i].sector_count; i++) { const format &f = formats[i]; if(size == (uint32_t) f.sector_count*f.sector_base_size*f.head_count) @@ -89,12 +94,13 @@ int d64_format::find_size(io_generic *io, uint32_t form_factor) const if(size == (uint32_t) (f.sector_count*f.sector_base_size*f.head_count) + f.sector_count) return i; } + return -1; } -int d64_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int d64_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor); + const int type = find_size(io, form_factor); if (type != -1) return 50; @@ -114,10 +120,11 @@ int d64_format::get_disk_id_offset(const format &f) return 0x165a2; } -void d64_format::get_disk_id(const format &f, io_generic *io, uint8_t &id1, uint8_t &id2) +void d64_format::get_disk_id(const format &f, util::random_read &io, uint8_t &id1, uint8_t &id2) { uint8_t id[2]; - io_generic_read(io, id, get_disk_id_offset(f), 2); + size_t actual; + io.read_at(get_disk_id_offset(f), id, 2, actual); id1 = id[0]; id2 = id[1]; } @@ -206,7 +213,7 @@ void d64_format::fix_end_gap(floppy_image_format_t::desc_e* desc, int remaining_ desc[22].p1 >>= remaining_size & 0x01; } -bool d64_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool d64_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int type = find_size(io, form_factor); if(type == -1) @@ -214,7 +221,9 @@ bool d64_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui const format &f = formats[type]; - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; std::vector<uint8_t> img; if(size == (uint32_t)f.sector_count*f.sector_base_size) { @@ -225,7 +234,8 @@ bool d64_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui img.resize(size); } - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); int track_offset = 0, error_offset = f.sector_count*f.sector_base_size; @@ -266,7 +276,7 @@ bool d64_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool d64_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool d64_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { const format &f = formats[0]; @@ -280,7 +290,8 @@ bool d64_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo build_sector_description(f, sectdata, 0, 0, sectors, sector_count); extract_sectors(image, f, sectors, track, head, sector_count); - io_generic_write(io, sectdata, offset, track_size); + size_t actual; + io.write_at(offset, sectdata, track_size, actual); } } diff --git a/src/lib/formats/d64_dsk.h b/src/lib/formats/d64_dsk.h index 665f6489a81..13f1bd4e91c 100644 --- a/src/lib/formats/d64_dsk.h +++ b/src/lib/formats/d64_dsk.h @@ -37,9 +37,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override { return true; } protected: @@ -61,12 +61,12 @@ protected: const format *formats; - int find_size(io_generic *io, uint32_t form_factor) const; + int find_size(util::random_read &io, uint32_t form_factor) const; virtual int get_physical_track(const format &f, int head, int track); virtual uint32_t get_cell_size(const format &f, int track); virtual int get_sectors_per_track(const format &f, int track); virtual int get_disk_id_offset(const format &f); - void get_disk_id(const format &f, io_generic *io, uint8_t &id1, uint8_t &id2); + void get_disk_id(const format &f, util::random_read &io, uint8_t &id1, uint8_t &id2); virtual int get_image_offset(const format &f, int head, int track); int compute_track_size(const format &f, int track); virtual int get_gap2(const format &f, int head, int track) { return f.gap_2; } diff --git a/src/lib/formats/d80_dsk.cpp b/src/lib/formats/d80_dsk.cpp index d350411b159..338f00292a9 100644 --- a/src/lib/formats/d80_dsk.cpp +++ b/src/lib/formats/d80_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/d80_dsk.h" +#include "ioprocs.h" + + d80_format::d80_format() : d64_format(file_formats), formats(nullptr) { } diff --git a/src/lib/formats/d88_dsk.cpp b/src/lib/formats/d88_dsk.cpp index 7c4eaa079dc..6e29f10df6a 100644 --- a/src/lib/formats/d88_dsk.cpp +++ b/src/lib/formats/d88_dsk.cpp @@ -29,11 +29,12 @@ * */ - #include <cassert> - #include "flopimg.h" #include "imageutl.h" +#include "ioprocs.h" + + #define D88_HEADER_LEN 0x2b0 struct d88_tag @@ -414,12 +415,15 @@ const char *d88_format::extensions() const return "d77,d88,1dd"; } -int d88_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int d88_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); - uint8_t h[32]; + uint64_t size; + if(io.length(size)) + return 0; - io_generic_read(io, h, 0, 32); + uint8_t h[32]; + size_t actual; + io.read_at(0, h, 32, actual); if((little_endianize_int32(*(uint32_t *)(h+0x1c)) == size) && (h[0x1b] == 0x00 || h[0x1b] == 0x10 || h[0x1b] == 0x20 || h[0x1b] == 0x30 || h[0x1b] == 0x40)) return 100; @@ -427,11 +431,12 @@ int d88_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool d88_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint8_t h[32]; + size_t actual; - io_generic_read(io, h, 0, 32); + uint8_t h[32]; + io.read_at(0, h, 32, actual); int cell_count = 0; int track_count = 0; @@ -477,9 +482,11 @@ bool d88_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return false; uint32_t track_pos[164]; - io_generic_read(io, track_pos, 32, 164*4); + io.read_at(32, track_pos, 164*4, actual); - uint64_t file_size = io_generic_size(io); + uint64_t file_size; + if(io.length(file_size)) + return false; for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { @@ -496,7 +503,7 @@ bool d88_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; uint8_t hs[16]; - io_generic_read(io, hs, pos, 16); + io.read_at(pos, hs, 16, actual); pos += 16; uint16_t size = little_endianize_int16(*(uint16_t *)(hs+14)); @@ -521,7 +528,7 @@ bool d88_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui if(size) { sects[i].data = sect_data + sdatapos; - io_generic_read(io, sects[i].data, pos, size); + io.read_at(pos, sects[i].data, size, actual); pos += size; sdatapos += size; @@ -536,7 +543,7 @@ bool d88_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool d88_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool d88_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/d88_dsk.h b/src/lib/formats/d88_dsk.h index c7c85fc1949..aeed5ed16e8 100644 --- a/src/lib/formats/d88_dsk.h +++ b/src/lib/formats/d88_dsk.h @@ -20,9 +20,9 @@ class d88_format : public floppy_image_format_t public: d88_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dcp_dsk.cpp b/src/lib/formats/dcp_dsk.cpp index b3beb40404f..7d419628bdc 100644 --- a/src/lib/formats/dcp_dsk.cpp +++ b/src/lib/formats/dcp_dsk.cpp @@ -20,10 +20,11 @@ *********************************************************************/ -#include <cassert> - #include "dcp_dsk.h" +#include "ioprocs.h" + + dcp_format::dcp_format() { } @@ -43,14 +44,18 @@ const char *dcp_format::extensions() const return "dcp,dcu"; } -int dcp_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dcp_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; + uint8_t h[0xa2]; int heads, tracks, spt, bps, count_tracks = 0; bool is_hdb = false; - io_generic_read(io, h, 0, 0xa2); + size_t actual; + io.read_at(0, h, 0xa2, actual); // First byte is the disk format (see below in load() for details) switch (h[0]) @@ -112,13 +117,14 @@ int dcp_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool dcp_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t h[0xa2]; int heads, tracks, spt, bps; bool is_hdb = false; - io_generic_read(io, h, 0, 0xa2); + io.read_at(0, h, 0xa2, actual); // First byte is the disk format: switch (h[0]) @@ -215,7 +221,7 @@ bool dcp_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { - io_generic_read(io, sect_data, 0xa2 + bps * spt * (track * heads + head), bps * spt); + io.read_at(0xa2 + bps * spt * (track * heads + head), sect_data, bps * spt, actual); for (int i = 0; i < spt; i++) { @@ -235,7 +241,7 @@ bool dcp_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui else // FIXME: the code below is untested, because no image was found... there might be some silly mistake in the disk geometry! { // Read Head 0 Track 0 is FM with 26 sectors of 128bytes instead of 256 - io_generic_read(io, sect_data, 0xa2, 128 * spt); + io.read_at(0xa2, sect_data, 128 * spt, actual); for (int i = 0; i < spt; i++) { @@ -252,7 +258,7 @@ bool dcp_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui build_pc_track_fm(0, 0, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, 128)); // Read Head 1 Track 0 is MFM with 26 sectors of 256bytes - io_generic_read(io, sect_data, 0xa2 + 128 * spt, bps * spt); + io.read_at(0xa2 + 128 * spt, sect_data, bps * spt, actual); for (int i = 0; i < spt; i++) { @@ -273,7 +279,7 @@ bool dcp_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for (int track = 1; track < tracks; track++) for (int head = 0; head < heads; head++) { - io_generic_read(io, sect_data, data_offs + bps * spt * ((track - 1) * heads + head), bps * spt); + io.read_at(data_offs + bps * spt * ((track - 1) * heads + head), sect_data, bps * spt, actual); for (int i = 0; i < spt; i++) { diff --git a/src/lib/formats/dcp_dsk.h b/src/lib/formats/dcp_dsk.h index c06396d527e..716814ffd48 100644 --- a/src/lib/formats/dcp_dsk.h +++ b/src/lib/formats/dcp_dsk.h @@ -20,8 +20,8 @@ class dcp_format : public floppy_image_format_t public: dcp_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dfi_dsk.cpp b/src/lib/formats/dfi_dsk.cpp index 409797e9583..607be56f741 100644 --- a/src/lib/formats/dfi_dsk.cpp +++ b/src/lib/formats/dfi_dsk.cpp @@ -13,7 +13,8 @@ #include "dfi_dsk.h" -#include <zlib.h> +#include "ioprocs.h" + #define NUMBER_OF_MULTIREADS 3 // thresholds for brickwall windowing @@ -56,24 +57,28 @@ bool dfi_format::supports_save() const return false; } -int dfi_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dfi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { char sign[4]; - io_generic_read(io, sign, 0, 4); + size_t actual; + io.read_at(0, sign, 4, actual); return memcmp(sign, "DFE2", 4) ? 0 : 100; } -bool dfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; char sign[4]; - io_generic_read(io, sign, 0, 4); - if (memcmp(sign, "DFER", 4) == 0) - { + io.read_at(0, sign, 4, actual); + if(memcmp(sign, "DFER", 4) == 0) { osd_printf_error("dfi_dsk: Old type Discferret image detected; the mess Discferret decoder will not handle this properly, bailing out!\n"); return false; } - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; + uint64_t pos = 4; std::vector<uint8_t> data; int onerev_time = 0; // time for one revolution, used to guess clock and rpm for DFE2 files @@ -81,7 +86,7 @@ bool dfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui int rpm=360; // drive rpm while(pos < size) { uint8_t h[10]; - io_generic_read(io, h, pos, 10); + io.read_at(pos, h, 10, actual); uint16_t track = (h[0] << 8) | h[1]; uint16_t head = (h[2] << 8) | h[3]; // Ignore sector @@ -97,7 +102,7 @@ bool dfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui data.resize(tsize); pos += 10; // skip the header, we already read it - io_generic_read(io, &data[0], pos, tsize); + io.read_at(pos, &data[0], tsize, actual); pos += tsize; // for next time we read, increment to the beginning of next header int index_time = 0; // what point the last index happened diff --git a/src/lib/formats/dfi_dsk.h b/src/lib/formats/dfi_dsk.h index d727f1d3c06..71b69c43d70 100644 --- a/src/lib/formats/dfi_dsk.h +++ b/src/lib/formats/dfi_dsk.h @@ -12,9 +12,9 @@ class dfi_format : public floppy_image_format_t public: dfi_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - // virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image); + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + // virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image); virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dim_dsk.cpp b/src/lib/formats/dim_dsk.cpp index 964f19ce028..04f6e3b8995 100644 --- a/src/lib/formats/dim_dsk.cpp +++ b/src/lib/formats/dim_dsk.cpp @@ -8,12 +8,14 @@ *********************************************************************/ -#include <cstring> -#include <cassert> - #include "dim_dsk.h" #include "basicdsk.h" +#include "ioprocs.h" + +#include <cstring> + + FLOPPY_IDENTIFY(dim_dsk_identify) { uint8_t dim_header[16]; @@ -132,11 +134,12 @@ const char *dim_format::extensions() const return "dim"; } -int dim_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dim_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[16]; - io_generic_read(io, h, 0xab, 16); + size_t actual; + io.read_at(0xab, h, 16, actual); if(strncmp((const char *)h, "DIFC HEADER", 11) == 0) return 100; @@ -144,14 +147,15 @@ int dim_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool dim_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dim_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; int offset = 0x100; uint8_t h; uint8_t track_total = 77; int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; - io_generic_read(io, &h, 0, 1); + io.read_at(0, &h, 1, actual); int spt, gap3, bps, size; switch(h) { @@ -211,7 +215,7 @@ bool dim_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = §_data[sdatapos]; - io_generic_read(io, sects[i].data, offset, bps); + io.read_at(offset, sects[i].data, bps, actual); offset += bps; sdatapos += bps; } @@ -223,7 +227,7 @@ bool dim_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool dim_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool dim_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/dim_dsk.h b/src/lib/formats/dim_dsk.h index e0227e2e221..5c84f329cb6 100644 --- a/src/lib/formats/dim_dsk.h +++ b/src/lib/formats/dim_dsk.h @@ -25,9 +25,9 @@ class dim_format : public floppy_image_format_t public: dim_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dip_dsk.cpp b/src/lib/formats/dip_dsk.cpp index a33d6fe35d6..17a7f856efe 100644 --- a/src/lib/formats/dip_dsk.cpp +++ b/src/lib/formats/dip_dsk.cpp @@ -14,10 +14,11 @@ *********************************************************************/ -#include <cassert> - #include "dip_dsk.h" +#include "ioprocs.h" + + dip_format::dip_format() { } @@ -37,9 +38,11 @@ const char *dip_format::extensions() const return "dip"; } -int dip_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dip_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; if (size == 0x134000 + 0x100) return 100; @@ -47,7 +50,7 @@ int dip_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool dip_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dip_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int heads, tracks, spt, bps; @@ -69,7 +72,8 @@ bool dip_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { - io_generic_read(io, sect_data, 0x100 + bps * spt * (track * heads + head), bps * spt); + size_t actual; + io.read_at(0x100 + bps * spt * (track * heads + head), sect_data, bps * spt, actual); for (int i = 0; i < spt; i++) { diff --git a/src/lib/formats/dip_dsk.h b/src/lib/formats/dip_dsk.h index 255e4e6c8a1..e310ef3f655 100644 --- a/src/lib/formats/dip_dsk.h +++ b/src/lib/formats/dip_dsk.h @@ -20,8 +20,8 @@ class dip_format : public floppy_image_format_t public: dip_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dmk_dsk.cpp b/src/lib/formats/dmk_dsk.cpp index 39c23223ec5..6a9e1dc0f0b 100644 --- a/src/lib/formats/dmk_dsk.cpp +++ b/src/lib/formats/dmk_dsk.cpp @@ -13,10 +13,10 @@ TODO: *********************************************************************/ -#include <cassert> - #include "dmk_dsk.h" +#include "ioprocs.h" + dmk_format::dmk_format() { @@ -41,14 +41,16 @@ const char *dmk_format::extensions() const } -int dmk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dmk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + uint64_t size; + if (io.length(size)) + return 0; + const int header_size = 16; uint8_t header[header_size]; - - uint64_t size = io_generic_size(io); - - io_generic_read(io, header, 0, header_size); + size_t actual; + io.read_at(0, header, header_size, actual); int tracks = header[1]; int track_size = ( header[3] << 8 ) | header[2]; @@ -81,12 +83,13 @@ int dmk_format::identify(io_generic *io, uint32_t form_factor, const std::vector } -bool dmk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; + const int header_size = 16; uint8_t header[header_size]; - - io_generic_read(io, header, 0, header_size); + io.read_at(0, header, header_size, actual); const int tracks = header[1]; const int track_size = ( header[3] << 8 ) | header[2]; @@ -128,7 +131,7 @@ bool dmk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui int dam_location[64]; // Read track - io_generic_read(io, &track_data[0], header_size + ( heads * track + head ) * track_size, track_size); + io.read_at(header_size + (heads * track + head) * track_size, &track_data[0], track_size, actual); for (int i = 0; i < 64; i++) { @@ -213,7 +216,7 @@ bool dmk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool dmk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool dmk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/dmk_dsk.h b/src/lib/formats/dmk_dsk.h index a2e7898dece..5485869b5b6 100644 --- a/src/lib/formats/dmk_dsk.h +++ b/src/lib/formats/dmk_dsk.h @@ -21,9 +21,9 @@ class dmk_format : public floppy_image_format_t public: dmk_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/ds9_dsk.cpp b/src/lib/formats/ds9_dsk.cpp index fdf4f5e2299..c97a2cced51 100644 --- a/src/lib/formats/ds9_dsk.cpp +++ b/src/lib/formats/ds9_dsk.cpp @@ -14,10 +14,10 @@ ************************************************************************/ -#include <cassert> - #include "formats/ds9_dsk.h" +#include "ioprocs.h" + static FLOPPY_IDENTIFY(ds9_dsk_identify) { @@ -97,33 +97,32 @@ const char *ds9_format::extensions() const return "ds9"; } -void ds9_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void ds9_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { - uint32_t expected_size = 0; - uint64_t size = io_generic_size(io); - head_count = 2; track_count = 80; sector_count = 21; - expected_size = 256 * track_count * head_count * sector_count; + uint32_t const expected_size = 256 * track_count * head_count * sector_count; - if (size >= expected_size) // standard format has 860160 bytes + uint64_t size; + if (!io.length(size) && (size >= expected_size)) // standard format has 860160 bytes return; track_count = head_count = sector_count = 0; } -int ds9_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ds9_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); - if (track_count) return 50; + if (track_count) + return 50; return 0; } -bool ds9_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool ds9_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -143,7 +142,8 @@ bool ds9_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui { for (int head = 0; head < head_count; head++) { - io_generic_read(io, sectdata, (track * head_count + head) * track_size, track_size); + size_t actual; + io.read_at((track * head_count + head) * track_size, sectdata, track_size, actual); generate_track(ds9_desc, track, head, sectors, sector_count, 104000, image); } } diff --git a/src/lib/formats/ds9_dsk.h b/src/lib/formats/ds9_dsk.h index 317134eab87..abdf152b2b3 100644 --- a/src/lib/formats/ds9_dsk.h +++ b/src/lib/formats/ds9_dsk.h @@ -5,9 +5,10 @@ formats/ds9_dsk.h *********************************************************************/ +#ifndef MAME_FORMATS_DS9_DSK_H +#define MAME_FORMATS_DS9_DSK_H -#ifndef DS9_DSK_H_ -#define DS9_DSK_H_ +#pragma once #include "flopimg.h" #include "formats/basicdsk.h" @@ -19,8 +20,8 @@ class ds9_format : public floppy_image_format_t public: ds9_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -30,9 +31,9 @@ public: static const desc_e ds9_desc[]; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; extern const floppy_format_type FLOPPY_DS9_FORMAT; -#endif /* DS9_DSK_H_ */ +#endif // MAME_FORMATS_DS9_DSK_H diff --git a/src/lib/formats/dsk_dsk.cpp b/src/lib/formats/dsk_dsk.cpp index dba11347887..fcf967edcb1 100644 --- a/src/lib/formats/dsk_dsk.cpp +++ b/src/lib/formats/dsk_dsk.cpp @@ -8,11 +8,12 @@ *********************************************************************/ -#include <cstring> -#include <cassert> - +#include "dsk_dsk.h" #include "imageutl.h" -#include "flopimg.h" + +#include "ioprocs.h" + +#include <cstring> #define MV_CPC "MV - CPC" #define EXTENDED "EXTENDED" @@ -270,7 +271,8 @@ FLOPPY_CONSTRUCT( dsk_dsk_construct ) return FLOPPY_ERROR_SUCCESS; } -#include "dsk_dsk.h" + + #define DSK_FORMAT_HEADER "MV - CPC" #define EXT_FORMAT_HEADER "EXTENDED CPC DSK" @@ -299,11 +301,12 @@ bool dsk_format::supports_save() const return false; } -int dsk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[16]; - io_generic_read(io, &header, 0, sizeof(header)); + size_t actual; + io.read_at(0, &header, sizeof(header), actual); if ( memcmp( header, DSK_FORMAT_HEADER, 8 ) ==0) { return 100; } @@ -344,14 +347,18 @@ struct sector_header #pragma pack() -bool dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; + uint8_t header[0x100]; bool extendformat = false; - uint64_t image_size = io_generic_size(io); + uint64_t image_size; + if (io.length(image_size)) + return false; - io_generic_read(io, &header, 0, sizeof(header)); + io.read_at(0, &header, sizeof(header), actual); if ( memcmp( header, EXT_FORMAT_HEADER, 16 ) ==0) { extendformat = true; } @@ -418,7 +425,7 @@ bool dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui if(track_offsets[(track<<1)+side] >= image_size) continue; track_header tr; - io_generic_read(io, &tr,track_offsets[(track<<1)+side],sizeof(tr)); + io.read_at(track_offsets[(track<<1)+side], &tr, sizeof(tr), actual); // skip if there are no sectors in this track if (tr.number_of_sector == 0) @@ -428,7 +435,7 @@ bool dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui int first_sector_code = -1; for(int j=0;j<tr.number_of_sector;j++) { sector_header sector; - io_generic_read(io, §or,track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j),sizeof(sector)); + io.read_at(track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector), actual); if (j == 0) first_sector_code = sector.sector_size_code; @@ -447,7 +454,7 @@ bool dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for(int j=0;j<tr.number_of_sector;j++) { sector_header sector; - io_generic_read(io, §or,track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j),sizeof(sector)); + io.read_at(track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector), actual); sects[j].track = sector.track; sects[j].head = sector.side; @@ -470,7 +477,7 @@ bool dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui if(!(sector.fdc_status_reg1 & 0x04)) { sects[j].data = sect_data + sdatapos; - io_generic_read(io, sects[j].data, pos, sects[j].actual_size); + io.read_at(pos, sects[j].data, sects[j].actual_size, actual); sdatapos += sects[j].actual_size; } else diff --git a/src/lib/formats/dsk_dsk.h b/src/lib/formats/dsk_dsk.h index a08e3955888..7d6b3bc43dc 100644 --- a/src/lib/formats/dsk_dsk.h +++ b/src/lib/formats/dsk_dsk.h @@ -19,8 +19,8 @@ class dsk_format : public floppy_image_format_t public: dsk_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/dvk_mx_dsk.cpp b/src/lib/formats/dvk_mx_dsk.cpp index 07d7a38cf95..08156d29e9c 100644 --- a/src/lib/formats/dvk_mx_dsk.cpp +++ b/src/lib/formats/dvk_mx_dsk.cpp @@ -18,11 +18,11 @@ ************************************************************************/ -#include <cassert> - -#include "flopimg.h" #include "formats/dvk_mx_dsk.h" +#include "ioprocs.h" + + const floppy_image_format_t::desc_e dvk_mx_format::dvk_mx_new_desc[] = { /* 01 */ { FM, 0x00, 8*2 }, // eight 0x0000 words /* 03 */ { FM, 0x00, 1 }, @@ -81,9 +81,14 @@ bool dvk_mx_format::supports_save() const return false; } -void dvk_mx_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void dvk_mx_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + { + track_count = head_count = sector_count = 0; + return; + } switch (size) { @@ -108,7 +113,7 @@ void dvk_mx_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &hea } } -int dvk_mx_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int dvk_mx_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; @@ -117,7 +122,8 @@ int dvk_mx_format::identify(io_generic *io, uint32_t form_factor, const std::vec if (track_count) { uint8_t sectdata[512]; - io_generic_read(io, sectdata, 512, 512); + size_t actual; + io.read_at(512, sectdata, 512, actual); // check value in RT-11 home block. see src/tools/imgtool/modules/rt11.cpp if (pick_integer_le(sectdata, 0724, 2) == 6) return 100; @@ -129,7 +135,7 @@ int dvk_mx_format::identify(io_generic *io, uint32_t form_factor, const std::vec return 0; } -bool dvk_mx_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool dvk_mx_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; @@ -150,7 +156,8 @@ bool dvk_mx_format::load(io_generic *io, uint32_t form_factor, const std::vector { for (int head = 0; head < head_count; head++) { - io_generic_read(io, sectdata, (track * head_count + head) * track_size, track_size); + size_t actual; + io.read_at((track * head_count + head) * track_size, sectdata, track_size, actual); generate_track(dvk_mx_new_desc, track, head, sectors, sector_count, 45824, image); } } diff --git a/src/lib/formats/dvk_mx_dsk.h b/src/lib/formats/dvk_mx_dsk.h index 38fd895d154..e20066fc3ec 100644 --- a/src/lib/formats/dvk_mx_dsk.h +++ b/src/lib/formats/dvk_mx_dsk.h @@ -5,9 +5,8 @@ formats/dvk_mx_dsk.h *********************************************************************/ - -#ifndef DVK_MX_DSK_H_ -#define DVK_MX_DSK_H_ +#ifndef MAME_FORMATS_DVK_MX_DSK_H +#define MAME_FORMATS_DVK_MX_DSK_H #pragma once @@ -19,8 +18,8 @@ class dvk_mx_format : public floppy_image_format_t public: dvk_mx_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -31,9 +30,9 @@ public: static const desc_e dvk_mx_new_desc[]; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; extern const floppy_format_type FLOPPY_DVK_MX_FORMAT; -#endif /* DVK_MX_DSK_H_ */ +#endif // MAME_FORMATS_DVK_MX_DSK_H diff --git a/src/lib/formats/esq16_dsk.cpp b/src/lib/formats/esq16_dsk.cpp index 10802d26495..b33e529fef2 100644 --- a/src/lib/formats/esq16_dsk.cpp +++ b/src/lib/formats/esq16_dsk.cpp @@ -10,10 +10,10 @@ *********************************************************************/ -#include <cassert> +#include "esq16_dsk.h" + +#include "ioprocs.h" -#include "flopimg.h" -#include "formats/esq16_dsk.h" const floppy_image_format_t::desc_e esqimg_format::esq_10_desc[] = { { MFM, 0x4e, 80 }, @@ -71,23 +71,23 @@ bool esqimg_format::supports_save() const return true; } -void esqimg_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void esqimg_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { - uint64_t size = io_generic_size(io); - track_count = 80; - head_count = 2; - sector_count = 10; - - uint32_t expected_size = 512 * track_count*head_count*sector_count; - if (size == expected_size) - { - return; - } + uint64_t size; + if(!io.length(size)) { + track_count = 80; + head_count = 2; + sector_count = 10; + uint32_t expected_size = 512 * track_count*head_count*sector_count; + if(size == expected_size) { + return; + } + } track_count = head_count = sector_count = 0; } -int esqimg_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int esqimg_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -97,7 +97,7 @@ int esqimg_format::identify(io_generic *io, uint32_t form_factor, const std::vec return 0; } -bool esqimg_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool esqimg_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -113,7 +113,8 @@ bool esqimg_format::load(io_generic *io, uint32_t form_factor, const std::vector int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { - io_generic_read(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual); generate_track(esq_10_desc, track, head, sectors, sector_count, 110528, image); } } @@ -123,7 +124,7 @@ bool esqimg_format::load(io_generic *io, uint32_t form_factor, const std::vector return true; } -bool esqimg_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool esqimg_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); @@ -144,7 +145,8 @@ bool esqimg_format::save(io_generic *io, const std::vector<uint32_t> &variants, for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); } } diff --git a/src/lib/formats/esq16_dsk.h b/src/lib/formats/esq16_dsk.h index 8cc49150d2c..2347d64f59c 100644 --- a/src/lib/formats/esq16_dsk.h +++ b/src/lib/formats/esq16_dsk.h @@ -21,9 +21,9 @@ class esqimg_format : public floppy_image_format_t public: esqimg_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -33,7 +33,7 @@ public: static const desc_e esq_10_desc[]; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; extern const floppy_format_type FLOPPY_ESQIMG_FORMAT; diff --git a/src/lib/formats/esq8_dsk.cpp b/src/lib/formats/esq8_dsk.cpp index f9dcb3d0727..952dd16edbd 100644 --- a/src/lib/formats/esq8_dsk.cpp +++ b/src/lib/formats/esq8_dsk.cpp @@ -12,10 +12,10 @@ *********************************************************************/ -#include <cassert> +#include "esq8_dsk.h" + +#include "ioprocs.h" -#include "flopimg.h" -#include "formats/esq8_dsk.h" const floppy_image_format_t::desc_e esq8img_format::esq_6_desc[] = { { MFM, 0x4e, 80 }, @@ -73,22 +73,24 @@ bool esq8img_format::supports_save() const return true; } -void esq8img_format::find_size(io_generic *io, int &track_count, int &head_count, int §or_count) +void esq8img_format::find_size(util::random_read &io, int &track_count, int &head_count, int §or_count) { - uint64_t size = io_generic_size(io); - track_count = 80; - head_count = 1; - sector_count = 6; - - if(size == 5632 * 80) + uint64_t size; + if(!io.length(size)) { - return; - } + track_count = 80; + head_count = 1; + sector_count = 6; + if(size == 5632 * 80) + { + return; + } + } track_count = head_count = sector_count = 0; } -int esq8img_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int esq8img_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -99,7 +101,7 @@ int esq8img_format::identify(io_generic *io, uint32_t form_factor, const std::ve return 0; } -bool esq8img_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool esq8img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -128,7 +130,8 @@ bool esq8img_format::load(io_generic *io, uint32_t form_factor, const std::vecto { for(int head=0; head < head_count; head++) { - io_generic_read(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual); generate_track(esq_6_desc, track, head, sectors, sector_count, 109376, image); } } @@ -138,7 +141,7 @@ bool esq8img_format::load(io_generic *io, uint32_t form_factor, const std::vecto return true; } -bool esq8img_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool esq8img_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { uint64_t file_offset = 0; int track_count, head_count, sector_count; @@ -175,7 +178,8 @@ bool esq8img_format::save(io_generic *io, const std::vector<uint32_t> &variants, return false; } - io_generic_write(io, sectors[sector].data(), file_offset, sector_expected_size); + size_t actual; + io.write_at(file_offset, sectors[sector].data(), sector_expected_size, actual); file_offset += sector_expected_size; } } diff --git a/src/lib/formats/esq8_dsk.h b/src/lib/formats/esq8_dsk.h index c4fe5a74f1b..aa09fd278a7 100644 --- a/src/lib/formats/esq8_dsk.h +++ b/src/lib/formats/esq8_dsk.h @@ -23,9 +23,9 @@ class esq8img_format : public floppy_image_format_t public: esq8img_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -35,7 +35,7 @@ public: static const desc_e esq_6_desc[]; private: - void find_size(io_generic *io, int &track_count, int &head_count, int §or_count); + void find_size(util::random_read &io, int &track_count, int &head_count, int §or_count); }; extern const floppy_format_type FLOPPY_ESQ8IMG_FORMAT; diff --git a/src/lib/formats/fdd_dsk.cpp b/src/lib/formats/fdd_dsk.cpp index df5fd3caa8c..8c8249c9452 100644 --- a/src/lib/formats/fdd_dsk.cpp +++ b/src/lib/formats/fdd_dsk.cpp @@ -31,10 +31,11 @@ *********************************************************************/ -#include <cassert> - #include "fdd_dsk.h" +#include "ioprocs.h" + + fdd_format::fdd_format() { } @@ -54,10 +55,11 @@ const char *fdd_format::extensions() const return "fdd"; } -int fdd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int fdd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[7]; - io_generic_read(io, h, 0, 7); + size_t actual; + io.read_at(0, h, 7, actual); if (strncmp((const char *)h, "VFD1.0", 6) == 0) return 100; @@ -65,7 +67,7 @@ int fdd_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool fdd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool fdd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t hsec[0x0c]; @@ -86,7 +88,8 @@ bool fdd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for (int sect = 0; sect < 26; sect++) { // read sector map for this sector - io_generic_read(io, hsec, pos, 0x0c); + size_t actual; + io.read_at(pos, hsec, 0x0c, actual); pos += 0x0c; if (hsec[0] == 0xff) // unformatted/unused sector @@ -118,10 +121,11 @@ bool fdd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui cur_sec_map = track * 26 + i; sector_size = 128 << sec_sizes[cur_sec_map]; + size_t actual; if (sec_offs[cur_sec_map] == 0xffffffff) memset(sect_data + cur_pos, fill_vals[cur_sec_map], sector_size); else - io_generic_read(io, sect_data + cur_pos, sec_offs[cur_sec_map], sector_size); + io.read_at(sec_offs[cur_sec_map], sect_data + cur_pos, sector_size, actual); sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; diff --git a/src/lib/formats/fdd_dsk.h b/src/lib/formats/fdd_dsk.h index ec013c58571..c1a3ae8a29b 100644 --- a/src/lib/formats/fdd_dsk.h +++ b/src/lib/formats/fdd_dsk.h @@ -20,8 +20,8 @@ class fdd_format : public floppy_image_format_t public: fdd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/flex_dsk.cpp b/src/lib/formats/flex_dsk.cpp index 692cc4bdc9d..4989a25e707 100644 --- a/src/lib/formats/flex_dsk.cpp +++ b/src/lib/formats/flex_dsk.cpp @@ -50,7 +50,11 @@ */ #include "flex_dsk.h" -#include "formats/imageutl.h" + +#include "imageutl.h" + +#include "ioprocs.h" + flex_format::flex_format() : wd177x_format(formats) { @@ -71,7 +75,7 @@ const char *flex_format::extensions() const return "dsk"; } -int flex_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int flex_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); @@ -80,17 +84,21 @@ int flex_format::identify(io_generic *io, uint32_t form_factor, const std::vecto return 0; } -int flex_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int flex_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return -1; + uint8_t boot0[256], boot1[256]; + size_t actual; // Look at the boot sector. // Density, sides, link?? - io_generic_read(io, &boot0, 256 * 0, sizeof(boot0)); - io_generic_read(io, &boot1, 256 * 1, sizeof(boot1)); + io.read_at(256 * 0, &boot0, sizeof(boot0), actual); + io.read_at(256 * 1, &boot1, sizeof(boot1), actual); // Look at the system information sector. - io_generic_read(io, &info, 256 * 2, sizeof(struct sysinfo_sector)); + io.read_at(256 * 2, &info, sizeof(struct sysinfo_sector), actual); LOG_FORMATS("FLEX floppy dsk: size %d bytes, %d total sectors, %d remaining bytes, expected form factor %x\n", (uint32_t)size, (uint32_t)size / 256, (uint32_t)size % 256, form_factor); diff --git a/src/lib/formats/flex_dsk.h b/src/lib/formats/flex_dsk.h index 094c6854b24..0048e4e088f 100644 --- a/src/lib/formats/flex_dsk.h +++ b/src/lib/formats/flex_dsk.h @@ -21,8 +21,8 @@ public: virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual const wd177x_format::format &get_track_format(const format &f, int head, int track) override; private: diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index 48c2fa1b610..55d00d1bb83 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -11,9 +11,10 @@ #include "flopimg.h" #include "imageutl.h" -#include "osdcore.h" #include "ioprocs.h" +#include "osdcore.h" + #include <cassert> #include <cctype> #include <climits> @@ -30,7 +31,7 @@ using util::BIT; struct floppy_image_legacy { - struct io_generic io = { 0 }; + util::random_read_write::ptr io = nullptr; const struct FloppyFormat *floppy_option = nullptr; struct FloppyCallbacks format = { 0 }; @@ -69,22 +70,20 @@ OPTION_GUIDE_START(floppy_option_guide) OPTION_GUIDE_END -static void floppy_close_internal(floppy_image_legacy *floppy, bool close_file); +static void floppy_close_internal(floppy_image_legacy *floppy); /********************************************************************* opening, closing and creating of floppy images *********************************************************************/ /* basic floppy_image_legacy initialization common to floppy_open() and floppy_create() */ -static floppy_image_legacy *floppy_init(void *fp, const struct io_procs *procs, int flags) +static floppy_image_legacy *floppy_init(util::random_read_write::ptr &&io, int flags) { floppy_image_legacy *floppy; floppy = new floppy_image_legacy; - floppy->io.file = fp; - floppy->io.procs = procs; - floppy->io.filler = 0xFF; + floppy->io = std::move(io); floppy->flags = (uint8_t) flags; return floppy; } @@ -93,7 +92,7 @@ static floppy_image_legacy *floppy_init(void *fp, const struct io_procs *procs, /* main code for identifying and maybe opening a disk image; not exposed * directly because this function is big and hideous */ -static floperr_t floppy_open_internal(void *fp, const struct io_procs *procs, const std::string &extension, +static floperr_t floppy_open_internal(util::random_read_write::ptr &&io, const std::string &extension, const struct FloppyFormat *floppy_options, int max_options, int flags, floppy_image_legacy **outfloppy, int *outoption) { @@ -104,7 +103,7 @@ static floperr_t floppy_open_internal(void *fp, const struct io_procs *procs, co int vote; size_t i; - floppy = floppy_init(fp, procs, flags); + floppy = floppy_init(std::move(io), flags); if (!floppy) { err = FLOPPY_ERROR_OUTOFMEMORY; @@ -163,7 +162,7 @@ done: /* if we have a floppy disk and we either errored or are not keeping it, close it */ if (floppy && (!outfloppy || err)) { - floppy_close_internal(floppy, false); + floppy_close_internal(floppy); floppy = nullptr; } @@ -176,31 +175,31 @@ done: -floperr_t floppy_identify(void *fp, const struct io_procs *procs, const char *extension, +floperr_t floppy_identify(util::random_read_write::ptr &&io, const char *extension, const struct FloppyFormat *formats, int *identified_format) { - return floppy_open_internal(fp, procs, extension, formats, INT_MAX, FLOPPY_FLAGS_READONLY, nullptr, identified_format); + return floppy_open_internal(std::move(io), extension, formats, INT_MAX, FLOPPY_FLAGS_READONLY, nullptr, identified_format); } -floperr_t floppy_open(void *fp, const struct io_procs *procs, const std::string &extension, +floperr_t floppy_open(util::random_read_write::ptr &&io, const std::string &extension, const struct FloppyFormat *format, int flags, floppy_image_legacy **outfloppy) { - return floppy_open_internal(fp, procs, extension, format, 1, flags, outfloppy, nullptr); + return floppy_open_internal(std::move(io), extension, format, 1, flags, outfloppy, nullptr); } -floperr_t floppy_open_choices(void *fp, const struct io_procs *procs, const std::string &extension, +floperr_t floppy_open_choices(util::random_read_write::ptr &&io, const std::string &extension, const struct FloppyFormat *formats, int flags, floppy_image_legacy **outfloppy) { - return floppy_open_internal(fp, procs, extension, formats, INT_MAX, flags, outfloppy, nullptr); + return floppy_open_internal(std::move(io), extension, formats, INT_MAX, flags, outfloppy, nullptr); } -floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct FloppyFormat *format, util::option_resolution *parameters, floppy_image_legacy **outfloppy) +floperr_t floppy_create(util::random_read_write::ptr &&io, const struct FloppyFormat *format, util::option_resolution *parameters, floppy_image_legacy **outfloppy) { floppy_image_legacy *floppy = nullptr; floperr_t err; @@ -210,7 +209,7 @@ floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct Flo assert(format); /* create the new image */ - floppy = floppy_init(fp, procs, 0); + floppy = floppy_init(std::move(io), 0); if (!floppy) { err = FLOPPY_ERROR_OUTOFMEMORY; @@ -266,28 +265,26 @@ floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct Flo done: if (err && floppy) { - floppy_close_internal(floppy, false); + floppy_close_internal(floppy); floppy = nullptr; } if (outfloppy) *outfloppy = floppy; else if (floppy) - floppy_close_internal(floppy, false); + floppy_close_internal(floppy); return err; } -static void floppy_close_internal(floppy_image_legacy *floppy, bool close_file) +static void floppy_close_internal(floppy_image_legacy *floppy) { if (floppy) { floppy_track_unload(floppy); if(floppy->floppy_option && floppy->floppy_option->destruct) floppy->floppy_option->destruct(floppy, floppy->floppy_option); - if (close_file) - io_generic_close(&floppy->io); delete floppy; } @@ -297,7 +294,7 @@ static void floppy_close_internal(floppy_image_legacy *floppy, bool close_file) void floppy_close(floppy_image_legacy *floppy) { - floppy_close_internal(floppy, true); + floppy_close_internal(floppy); } @@ -332,14 +329,16 @@ void *floppy_create_tag(floppy_image_legacy *floppy, size_t tagsize) uint8_t floppy_get_filler(floppy_image_legacy *floppy) { - return floppy->io.filler; + // FIXME: remove this function, it's here for legacy reasons + // the caller actually sets the filler byte - in practice it's always 0xff but there's no actual guarantee + return 0xff; } -void floppy_set_filler(floppy_image_legacy *floppy, uint8_t filler) +util::random_read_write &floppy_get_io(floppy_image_legacy *floppy) { - floppy->io.filler = filler; + return *floppy->io; } @@ -350,28 +349,42 @@ void floppy_set_filler(floppy_image_legacy *floppy, uint8_t filler) void floppy_image_read(floppy_image_legacy *floppy, void *buffer, uint64_t offset, size_t length) { - io_generic_read(&floppy->io, buffer, offset, length); + size_t actual; + floppy->io->read_at(offset, buffer, length, actual); } void floppy_image_write(floppy_image_legacy *floppy, const void *buffer, uint64_t offset, size_t length) { - io_generic_write(&floppy->io, buffer, offset, length); + size_t actual; + floppy->io->write_at(offset, buffer, length, actual); } void floppy_image_write_filler(floppy_image_legacy *floppy, uint8_t filler, uint64_t offset, size_t length) { - io_generic_write_filler(&floppy->io, filler, offset, length); + uint8_t buffer[512]; + memset(buffer, filler, std::min(sizeof(buffer), length)); + + while (length) + { + size_t const block = std::min(sizeof(buffer), length); + size_t actual; + floppy->io->write_at(offset, buffer, block, actual); + offset += block; + length -= block; + } } uint64_t floppy_image_size(floppy_image_legacy *floppy) { - return io_generic_size(&floppy->io); + uint64_t result; + floppy->io->length(result); + return result; } @@ -976,7 +989,7 @@ bool floppy_image_format_t::has_variant(const std::vector<uint32_t> &variants, u return false; } -bool floppy_image_format_t::save(io_generic *, const std::vector<uint32_t> &, floppy_image *) +bool floppy_image_format_t::save(util::random_read_write &io, const std::vector<uint32_t> &, floppy_image *) { return false; } diff --git a/src/lib/formats/flopimg.h b/src/lib/formats/flopimg.h index 101d9bd86bd..6279def82f8 100644 --- a/src/lib/formats/flopimg.h +++ b/src/lib/formats/flopimg.h @@ -12,11 +12,13 @@ #pragma once -#include "osdcore.h" -#include "ioprocs.h" -#include "opresolv.h" #include "coretmpl.h" +#include "opresolv.h" +#include "utilfwd.h" + +#include "osdcore.h" +#include <memory> #include <vector> #ifndef LOG_FORMATS @@ -166,20 +168,20 @@ LEGACY_FLOPPY_OPTIONS_EXTERN(default); OPTION_GUIDE_EXTERN(floppy_option_guide); /* opening, closing and creating of floppy images */ -floperr_t floppy_open(void *fp, const struct io_procs *procs, const std::string &extension, const struct FloppyFormat *format, int flags, floppy_image_legacy **outfloppy); -floperr_t floppy_open_choices(void *fp, const struct io_procs *procs, const std::string &extension, const struct FloppyFormat *formats, int flags, floppy_image_legacy **outfloppy); -floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct FloppyFormat *format, util::option_resolution *parameters, floppy_image_legacy **outfloppy); +floperr_t floppy_open(std::unique_ptr<util::random_read_write> &&io, const std::string &extension, const struct FloppyFormat *format, int flags, floppy_image_legacy **outfloppy); +floperr_t floppy_open_choices(std::unique_ptr<util::random_read_write> &&io, const std::string &extension, const struct FloppyFormat *formats, int flags, floppy_image_legacy **outfloppy); +floperr_t floppy_create(std::unique_ptr<util::random_read_write> &&io, const struct FloppyFormat *format, util::option_resolution *parameters, floppy_image_legacy **outfloppy); void floppy_close(floppy_image_legacy *floppy); /* useful for identifying a floppy image */ -floperr_t floppy_identify(void *fp, const struct io_procs *procs, const char *extension, const struct FloppyFormat *formats, int *identified_format); +floperr_t floppy_identify(std::unique_ptr<util::random_read_write> &&io, const char *extension, const struct FloppyFormat *formats, int *identified_format); /* functions useful within format constructors */ void *floppy_tag(floppy_image_legacy *floppy); void *floppy_create_tag(floppy_image_legacy *floppy, size_t tagsize); struct FloppyCallbacks *floppy_callbacks(floppy_image_legacy *floppy); uint8_t floppy_get_filler(floppy_image_legacy *floppy); -void floppy_set_filler(floppy_image_legacy *floppy, uint8_t filler); +util::random_read_write &floppy_get_io(floppy_image_legacy *floppy); /* calls for accessing disk image data */ floperr_t floppy_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int offset, void *buffer, size_t buffer_len); @@ -235,7 +237,7 @@ public: @param variants the variants from floppy_image the drive can handle @return 1 if image valid, 0 otherwise. */ - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) = 0; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) = 0; /*! @brief Load an image. The load function opens an image file and converts it to the @@ -247,7 +249,7 @@ public: @param image output buffer for data in MESS internal format. @return true on success, false otherwise. */ - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) = 0; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) = 0; /*! @brief Save an image. The save function writes back an image from the MESS internal @@ -257,7 +259,7 @@ public: @param image source buffer containing data in MESS internal format. @return true on success, false otherwise. */ - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image); + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image); //! @returns string containing name of format. virtual const char *name() const = 0; diff --git a/src/lib/formats/fsd_dsk.cpp b/src/lib/formats/fsd_dsk.cpp index c5ebd243875..ffb23035420 100644 --- a/src/lib/formats/fsd_dsk.cpp +++ b/src/lib/formats/fsd_dsk.cpp @@ -10,6 +10,8 @@ #include "fsd_dsk.h" +#include "ioprocs.h" + /********************************************************************* @@ -83,11 +85,12 @@ bool fsd_format::supports_save() const return false; } -int fsd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int fsd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[3]; - io_generic_read(io, h, 0, 3); + size_t actual; + io.read_at(0, h, 3, actual); if (memcmp(h, "FSD", 3) == 0) { return 100; } @@ -95,16 +98,19 @@ int fsd_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool fsd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool fsd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { const char* result[255]; result[0x00] = "OK"; result[0x0e] = "Data CRC Error"; result[0x20] = "Deleted Data"; - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); uint64_t pos; std::string title; diff --git a/src/lib/formats/fsd_dsk.h b/src/lib/formats/fsd_dsk.h index ee2c4aa466c..779ee28ec02 100644 --- a/src/lib/formats/fsd_dsk.h +++ b/src/lib/formats/fsd_dsk.h @@ -33,8 +33,8 @@ public: virtual const char *extensions() const override; virtual bool supports_save() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; }; extern const floppy_format_type FLOPPY_FSD_FORMAT; diff --git a/src/lib/formats/g64_dsk.cpp b/src/lib/formats/g64_dsk.cpp index 02098db88e0..8e6b9c75e44 100644 --- a/src/lib/formats/g64_dsk.cpp +++ b/src/lib/formats/g64_dsk.cpp @@ -12,6 +12,8 @@ #include "formats/g64_dsk.h" +#include "ioprocs.h" + #define G64_FORMAT_HEADER "GCR-1541" @@ -27,22 +29,27 @@ const uint32_t g64_format::c1541_cell_size[] = 3250 // 16MHz/13/4 }; -int g64_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int g64_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { char h[8]; - io_generic_read(io, h, 0, 8); + size_t actual; + io.read_at(0, h, 8, actual); if (!memcmp(h, G64_FORMAT_HEADER, 8)) return 100; return 0; } -bool g64_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool g64_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; + std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); if (img[POS_VERSION]) { @@ -109,15 +116,19 @@ int g64_format::generate_bitstream(int track, int head, int speed_zone, std::vec return ((actual_cell_size >= cell_size-10) && (actual_cell_size <= cell_size+10)) ? speed_zone : -1; } -bool g64_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool g64_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { + uint8_t const zerofill[] = { 0x00, 0x00, 0x00, 0x00 }; + std::vector<uint8_t> const prefill(TRACK_LENGTH, 0xff); + size_t actual; + int tracks, heads; image->get_actual_geometry(tracks, heads); tracks = TRACK_COUNT * heads; // write header uint8_t header[] = { 'G', 'C', 'R', '-', '1', '5', '4', '1', 0x00, static_cast<uint8_t>(tracks), TRACK_LENGTH & 0xff, TRACK_LENGTH >> 8 }; - io_generic_write(io, header, POS_SIGNATURE, sizeof(header)); + io.write_at(POS_SIGNATURE, header, sizeof(header), actual); // write tracks for (int head = 0; head < heads; head++) { @@ -126,12 +137,12 @@ bool g64_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo std::vector<bool> trackbuf; for (int track = 0; track < TRACK_COUNT; track++) { - uint32_t tpos = POS_TRACK_OFFSET + (track * 4); - uint32_t spos = tpos + (tracks * 4); - uint32_t dpos = POS_TRACK_OFFSET + (tracks * 4 * 2) + (tracks_written * TRACK_LENGTH); + uint32_t const tpos = POS_TRACK_OFFSET + (track * 4); + uint32_t const spos = tpos + (tracks * 4); + uint32_t const dpos = POS_TRACK_OFFSET + (tracks * 4 * 2) + (tracks_written * TRACK_LENGTH); - io_generic_write_filler(io, 0x00, tpos, 4); - io_generic_write_filler(io, 0x00, spos, 4); + io.write_at(tpos, zerofill, 4, actual); + io.write_at(spos, zerofill, 4, actual); if (image->get_buffer(track, head).size() <= 1) continue; @@ -163,11 +174,11 @@ bool g64_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo place_integer_le(speed_offset, 0, 4, speed_zone); place_integer_le(track_length, 0, 2, packed.size()); - io_generic_write(io, track_offset, tpos, 4); - io_generic_write(io, speed_offset, spos, 4); - io_generic_write_filler(io, 0xff, dpos, TRACK_LENGTH); - io_generic_write(io, track_length, dpos, 2); - io_generic_write(io, packed.data(), dpos + 2, packed.size()); + io.write_at(tpos, track_offset, 4, actual); + io.write_at(spos, speed_offset, 4, actual); + io.write_at(dpos, prefill.data(), TRACK_LENGTH, actual); + io.write_at(dpos, track_length, 2, actual); + io.write_at(dpos + 2, packed.data(), packed.size(), actual); tracks_written++; } diff --git a/src/lib/formats/g64_dsk.h b/src/lib/formats/g64_dsk.h index 6691146c70e..fcd48d96796 100644 --- a/src/lib/formats/g64_dsk.h +++ b/src/lib/formats/g64_dsk.h @@ -20,9 +20,9 @@ class g64_format : public floppy_image_format_t public: g64_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/hpi_dsk.cpp b/src/lib/formats/hpi_dsk.cpp index d9fc788fd45..bdccc66803d 100644 --- a/src/lib/formats/hpi_dsk.cpp +++ b/src/lib/formats/hpi_dsk.cpp @@ -48,6 +48,7 @@ #include "hpi_dsk.h" #include "coretmpl.h" // BIT +#include "ioprocs.h" // Debugging @@ -78,9 +79,12 @@ hpi_format::hpi_format() (void)HPI_RED_IMAGE_SIZE; } -int hpi_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int hpi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) { + return 0; + } // we try to stay back and give only 50 points, since another image // format may also have images of the same size (there is no header and no @@ -142,12 +146,15 @@ bool hpi_format::geometry_from_size(uint64_t image_size , unsigned& heads , unsi } } -bool hpi_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool hpi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { unsigned heads; unsigned cylinders; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) { + return false; + } if (!geometry_from_size(size, heads, cylinders)) { return false; } @@ -161,7 +168,8 @@ bool hpi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui // Suck in the whole image std::vector<uint8_t> image_data(size); - io_generic_read(io, (void *)image_data.data(), 0, size); + size_t actual; + io.read_at(0, image_data.data(), size, actual); // Get interleave factor from image unsigned il = (unsigned)image_data[ IL_OFFSET ] * 256 + image_data[ IL_OFFSET + 1 ]; @@ -191,7 +199,7 @@ bool hpi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool hpi_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool hpi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int tracks; int heads; @@ -206,7 +214,8 @@ bool hpi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo while (get_next_sector(bitstream , pos , track_no , head_no , sector_no , sector_data)) { if (track_no == cyl && head_no == head && sector_no < HPI_SECTORS) { unsigned offset_in_image = chs_to_lba(cyl, head, sector_no, heads) * HPI_SECTOR_SIZE; - io_generic_write(io, sector_data, offset_in_image, HPI_SECTOR_SIZE); + size_t actual; + io.write_at(offset_in_image, sector_data, HPI_SECTOR_SIZE, actual); } } } diff --git a/src/lib/formats/hpi_dsk.h b/src/lib/formats/hpi_dsk.h index 38c70e91c33..ca8aa1ffe11 100644 --- a/src/lib/formats/hpi_dsk.h +++ b/src/lib/formats/hpi_dsk.h @@ -28,9 +28,9 @@ class hpi_format : public floppy_image_format_t public: hpi_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; diff --git a/src/lib/formats/hti_tape.cpp b/src/lib/formats/hti_tape.cpp index 7f77e3f99df..8fbaeef91cc 100644 --- a/src/lib/formats/hti_tape.cpp +++ b/src/lib/formats/hti_tape.cpp @@ -10,6 +10,8 @@ #include "imageutl.h" +#include "ioprocs.h" + static constexpr uint32_t OLD_FILE_MAGIC = 0x5441434f; // Magic value at start of old-format image file: "TACO" static constexpr uint32_t FILE_MAGIC_DELTA = 0x48544930; // Magic value at start of delta-modulation image file: "HTI0" @@ -47,22 +49,25 @@ hti_format_t::hti_format_t() clear_tape(); } -bool hti_format_t::load_tape(io_generic *io) +bool hti_format_t::load_tape(util::random_read &io) { + if (io.seek(0, SEEK_SET)) { + return false; + } + + size_t actual; uint8_t tmp[ 4 ]; - io_generic_read(io, tmp, 0, 4); + io.read(tmp, 4, actual); auto magic = pick_integer_be(tmp , 0 , 4); if (((m_img_format == HTI_DELTA_MOD_16_BITS || m_img_format == HTI_DELTA_MOD_17_BITS) && magic != FILE_MAGIC_DELTA && magic != OLD_FILE_MAGIC) || (m_img_format == HTI_MANCHESTER_MOD && magic != FILE_MAGIC_MANCHESTER)) { return false; } - uint64_t offset = 4; - for (unsigned i = 0; i < no_of_tracks(); i++) { tape_track_t& track = m_tracks[ i ]; - if (!load_track(io , offset , track , magic == OLD_FILE_MAGIC)) { + if (!load_track(io, track, magic == OLD_FILE_MAGIC)) { clear_tape(); return false; } @@ -71,14 +76,15 @@ bool hti_format_t::load_tape(io_generic *io) return true; } -void hti_format_t::save_tape(io_generic *io) +void hti_format_t::save_tape(util::random_read_write &io) { + io.seek(0, SEEK_SET); + + size_t actual; uint8_t tmp[ 4 ]; place_integer_be(tmp, 0, 4, m_img_format == HTI_MANCHESTER_MOD ? FILE_MAGIC_MANCHESTER : FILE_MAGIC_DELTA); - io_generic_write(io, tmp, 0, 4); - - uint64_t offset = 4; + io.write(tmp, 4, actual); for (unsigned i = 0; i < no_of_tracks(); i++) { const tape_track_t& track = m_tracks[ i ]; @@ -87,18 +93,17 @@ void hti_format_t::save_tape(io_generic *io) tape_track_t::const_iterator it_start; for (tape_track_t::const_iterator it = track.cbegin(); it != track.cend(); ++it) { if (it->first != next_pos) { - dump_sequence(io , offset , it_start , n_words); + dump_sequence(io, it_start, n_words); it_start = it; n_words = 0; } next_pos = it->first + word_length(it->second); n_words++; } - dump_sequence(io , offset , it_start , n_words); + dump_sequence(io, it_start, n_words); // End of track place_integer_le(tmp, 0, 4, (uint32_t)-1); - io_generic_write(io, tmp, offset, 4); - offset += 4; + io.write(tmp, 4, actual); } } @@ -374,8 +379,9 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , return n_gaps == 0; } -bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& track , bool old_format) +bool hti_format_t::load_track(util::random_read &io , tape_track_t& track , bool old_format) { + size_t actual; uint8_t tmp[ 4 ]; uint32_t tmp32; tape_pos_t delta_pos = 0; @@ -385,8 +391,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& while (1) { // Read no. of words to follow - io_generic_read(io, tmp, offset, 4); - offset += 4; + io.read(tmp, 4, actual); tmp32 = pick_integer_le(tmp, 0, 4); @@ -398,8 +403,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& unsigned n_words = tmp32; // Read tape position of block - io_generic_read(io, tmp, offset, 4); - offset += 4; + io.read(tmp, 4, actual); tmp32 = pick_integer_le(tmp, 0, 4); @@ -411,8 +415,7 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& for (unsigned i = 0; i < n_words; i++) { uint16_t tmp16; - io_generic_read(io, tmp, offset, 2); - offset += 2; + io.read(tmp, 2, actual); tmp16 = pick_integer_le(tmp, 0, 2); if (!old_format) { @@ -469,19 +472,18 @@ bool hti_format_t::load_track(io_generic *io , uint64_t& offset , tape_track_t& } } -void hti_format_t::dump_sequence(io_generic *io , uint64_t& offset , tape_track_t::const_iterator it_start , unsigned n_words) +void hti_format_t::dump_sequence(util::random_read_write &io , tape_track_t::const_iterator it_start , unsigned n_words) { if (n_words) { + size_t actual; uint8_t tmp[ 8 ]; place_integer_le(tmp, 0, 4, n_words); place_integer_le(tmp, 4, 4, it_start->first); - io_generic_write(io, tmp, offset, 8); - offset += 8; + io.write(tmp, 8, actual); for (unsigned i = 0; i < n_words; i++) { place_integer_le(tmp, 0, 2, it_start->second); - io_generic_write(io, tmp, offset, 2); - offset += 2; + io.write(tmp, 2, actual); ++it_start; } } diff --git a/src/lib/formats/hti_tape.h b/src/lib/formats/hti_tape.h index 7725b87fa2a..373c971d174 100644 --- a/src/lib/formats/hti_tape.h +++ b/src/lib/formats/hti_tape.h @@ -13,10 +13,12 @@ #pragma once -#include "ioprocs.h" +#include "utilfwd.h" +#include <cstdint> #include <map> + class hti_format_t { public: @@ -71,8 +73,8 @@ public: // Return number of tracks unsigned no_of_tracks() const { return m_img_format == HTI_MANCHESTER_MOD ? 1 : 2; } - bool load_tape(io_generic *io); - void save_tape(io_generic *io); + bool load_tape(util::random_read &io); + void save_tape(util::random_read_write &io); void clear_tape(); // Return physical length of a bit on tape @@ -127,8 +129,8 @@ private: // Image format image_format_t m_img_format; - bool load_track(io_generic *io , uint64_t& offset , tape_track_t& track , bool old_format); - static void dump_sequence(io_generic *io , uint64_t& offset , tape_track_t::const_iterator it_start , unsigned n_words); + bool load_track(util::random_read &io , tape_track_t& track , bool old_format); + static void dump_sequence(util::random_read_write &io , tape_track_t::const_iterator it_start , unsigned n_words); tape_pos_t word_end_pos(const track_iterator_t& it) const; void adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) const; diff --git a/src/lib/formats/hxchfe_dsk.cpp b/src/lib/formats/hxchfe_dsk.cpp index 68360f4e9bb..15598bbd746 100644 --- a/src/lib/formats/hxchfe_dsk.cpp +++ b/src/lib/formats/hxchfe_dsk.cpp @@ -101,6 +101,9 @@ #include "hxchfe_dsk.h" +#include "ioprocs.h" + + #define HFE_FORMAT_HEADER "HXCPICFE" #define HEADER_LENGTH 512 @@ -144,19 +147,21 @@ bool hfe_format::supports_save() const return true; } -int hfe_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int hfe_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[8]; - io_generic_read(io, &header, 0, sizeof(header)); + size_t actual; + io.read_at(0, &header, sizeof(header), actual); if ( memcmp( header, HFE_FORMAT_HEADER, 8 ) ==0) { return 100; } return 0; } -bool hfe_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t header[HEADER_LENGTH]; uint8_t track_table[TRACK_TABLE_LENGTH]; @@ -164,7 +169,7 @@ bool hfe_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui image->get_maximal_geometry(drivecyl, driveheads); // read header - io_generic_read(io, header, 0, HEADER_LENGTH); + io.read_at(0, header, HEADER_LENGTH, actual); // get values // Format revision must be 0 @@ -236,7 +241,7 @@ bool hfe_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui // read track lookup table (multiple of 512) int table_offset = (header[18] & 0xff) | ((header[19] & 0xff)<<8); - io_generic_read(io, track_table, table_offset<<9, TRACK_TABLE_LENGTH); + io.read_at(table_offset<<9, track_table, TRACK_TABLE_LENGTH, actual); for (int i=0; i < m_cylinders; i++) { @@ -252,7 +257,7 @@ bool hfe_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui // The HFE format defines an interleave of the two sides per cylinder // at every 256 bytes cylinder_buffer.resize(m_cyl_length[cyl]); - io_generic_read(io, &cylinder_buffer[0], m_cyl_offset[cyl]<<9, m_cyl_length[cyl]); + io.read_at(m_cyl_offset[cyl]<<9, &cylinder_buffer[0], m_cyl_length[cyl], actual); generate_track_from_hfe_bitstream(cyl, 0, samplelength, &cylinder_buffer[0], m_cyl_length[cyl], image); if (m_heads == 2) @@ -412,8 +417,9 @@ void hfe_format::generate_track_from_hfe_bitstream(int cyl, int head, int sample image->set_write_splice_position(cyl, head, 0, 0); } -bool hfe_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool hfe_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; std::vector<uint8_t> cylbuf; // Create a buffer that is big enough to handle HD formats. We don't @@ -484,7 +490,7 @@ bool hfe_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo header[13] = (m_bit_rate >> 8) & 0xff; // Now write the header - io_generic_write(io, header, 0, HEADER_LENGTH); + io.write_at(0, header, HEADER_LENGTH, actual); // Set up the track lookup table // We need the encoding value to be sure about the track length @@ -505,10 +511,10 @@ bool hfe_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo for (int i=m_cylinders*4; i < TRACK_TABLE_LENGTH; i++) track_table[i] = 0xff; - io_generic_write(io, track_table, 0x200, TRACK_TABLE_LENGTH); + io.write_at(0x200, track_table, TRACK_TABLE_LENGTH, actual); } // Write the current cylinder - io_generic_write(io, &cylbuf[0], m_cyl_offset[cyl]<<9, (m_cyl_length[cyl] + 0x1ff) & 0xfe00); + io.write_at(m_cyl_offset[cyl]<<9, &cylbuf[0], (m_cyl_length[cyl] + 0x1ff) & 0xfe00, actual); } return true; } diff --git a/src/lib/formats/hxchfe_dsk.h b/src/lib/formats/hxchfe_dsk.h index 9d2dbdeae77..4ea98ed861c 100644 --- a/src/lib/formats/hxchfe_dsk.h +++ b/src/lib/formats/hxchfe_dsk.h @@ -47,9 +47,9 @@ public: hfe_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/hxcmfm_dsk.cpp b/src/lib/formats/hxcmfm_dsk.cpp index b6845b28e4a..e7bf03acd2f 100644 --- a/src/lib/formats/hxcmfm_dsk.cpp +++ b/src/lib/formats/hxcmfm_dsk.cpp @@ -1,10 +1,11 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert -#include <cassert> - #include "hxcmfm_dsk.h" +#include "ioprocs.h" + + #define MFM_FORMAT_HEADER "HXCMFM" #pragma pack(1) @@ -57,24 +58,26 @@ bool mfm_format::supports_save() const return true; } -int mfm_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int mfm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[7]; - io_generic_read(io, &header, 0, sizeof(header)); + size_t actual; + io.read_at(0, &header, sizeof(header), actual); if ( memcmp( header, MFM_FORMAT_HEADER, 6 ) ==0) { return 100; } return 0; } -bool mfm_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool mfm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; MFMIMG header; MFMTRACKIMG trackdesc; // read header - io_generic_read(io, &header, 0, sizeof(header)); + io.read_at(0, &header, sizeof(header), actual); int drivecyl, driveheads; image->get_maximal_geometry(drivecyl, driveheads); @@ -86,12 +89,12 @@ bool mfm_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for(int side=0; side < header.number_of_side; side++) { if (!skip_odd || track%2 == 0) { // read location of - io_generic_read(io, &trackdesc,(header.mfmtracklistoffset)+( counter *sizeof(trackdesc)),sizeof(trackdesc)); + io.read_at((header.mfmtracklistoffset)+( counter *sizeof(trackdesc)), &trackdesc, sizeof(trackdesc), actual); trackbuf.resize(trackdesc.mfmtracksize); // actual data read - io_generic_read(io, &trackbuf[0], trackdesc.mfmtrackoffset, trackdesc.mfmtracksize); + io.read_at(trackdesc.mfmtrackoffset, &trackbuf[0], trackdesc.mfmtracksize, actual); if (skip_odd) { generate_track_from_bitstream(track/2, side, &trackbuf[0], trackdesc.mfmtracksize*8, image); @@ -109,9 +112,10 @@ bool mfm_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool mfm_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool mfm_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { // TODO: HD support + size_t actual; MFMIMG header; int track_count, head_count; image->get_actual_geometry(track_count, head_count); @@ -124,7 +128,7 @@ bool mfm_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo header.floppyiftype = 4; header.mfmtracklistoffset = sizeof(MFMIMG); - io_generic_write(io, &header, 0, sizeof(MFMIMG)); + io.write_at(0, &header, sizeof(MFMIMG), actual); int tpos = sizeof(MFMIMG); int dpos = tpos + track_count*head_count*sizeof(MFMTRACKIMG); @@ -143,8 +147,8 @@ bool mfm_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo trackdesc.mfmtracksize = packed.size(); trackdesc.mfmtrackoffset = dpos; - io_generic_write(io, &trackdesc, tpos, sizeof(MFMTRACKIMG)); - io_generic_write(io, packed.data(), dpos, packed.size()); + io.write_at(tpos, &trackdesc, sizeof(MFMTRACKIMG), actual); + io.write_at(dpos, packed.data(), packed.size(), actual); tpos += sizeof(MFMTRACKIMG); dpos += packed.size(); diff --git a/src/lib/formats/hxcmfm_dsk.h b/src/lib/formats/hxcmfm_dsk.h index a6f884ab03e..c42190f3aae 100644 --- a/src/lib/formats/hxcmfm_dsk.h +++ b/src/lib/formats/hxcmfm_dsk.h @@ -19,9 +19,9 @@ class mfm_format : public floppy_image_format_t public: mfm_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/ibmxdf_dsk.cpp b/src/lib/formats/ibmxdf_dsk.cpp index b18ffad63dc..5a44290a337 100644 --- a/src/lib/formats/ibmxdf_dsk.cpp +++ b/src/lib/formats/ibmxdf_dsk.cpp @@ -32,6 +32,8 @@ #include "ibmxdf_dsk.h" +#include "ioprocs.h" + ibmxdf_format::ibmxdf_format() : wd177x_format(formats) { @@ -52,7 +54,7 @@ const char *ibmxdf_format::extensions() const return "xdf,img"; } -int ibmxdf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ibmxdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); @@ -61,9 +63,11 @@ int ibmxdf_format::identify(io_generic *io, uint32_t form_factor, const std::vec return 0; } -int ibmxdf_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ibmxdf_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return -1; if (size != 1884160) return -1; @@ -173,7 +177,7 @@ const ibmxdf_format::format ibmxdf_format::formats_head1_track0[] = { {} }; -bool ibmxdf_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool ibmxdf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int type = find_size(io, form_factor, variants); if(type == -1) @@ -207,8 +211,9 @@ bool ibmxdf_format::load(io_generic *io, uint32_t form_factor, const std::vector desc[16].p1 = get_track_dam_mfm(tf, head, track); build_sector_description(tf, sectdata, sectors, track, head); - int track_size = compute_track_size(f) * 2; // read both sides at once - io_generic_read(io, sectdata, get_image_offset(f, head, track), track_size); + int const track_size = compute_track_size(f) * 2; // read both sides at once + size_t actual; + io.read_at(get_image_offset(f, head, track), sectdata, track_size, actual); generate_track(desc, track, head, sectors, tf.sector_count, total_size, image); } diff --git a/src/lib/formats/ibmxdf_dsk.h b/src/lib/formats/ibmxdf_dsk.h index 6d37142ac30..dbb448f8ad3 100644 --- a/src/lib/formats/ibmxdf_dsk.h +++ b/src/lib/formats/ibmxdf_dsk.h @@ -23,11 +23,11 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override { return false; } - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const wd177x_format::format &get_track_format(const format &f, int head, int track) override; diff --git a/src/lib/formats/imd_dsk.cpp b/src/lib/formats/imd_dsk.cpp index b3d4eac8229..b0e9a4159d9 100644 --- a/src/lib/formats/imd_dsk.cpp +++ b/src/lib/formats/imd_dsk.cpp @@ -10,7 +10,8 @@ #include "imd_dsk.h" -#include <cassert> +#include "ioprocs.h" + #include <cstring> @@ -409,25 +410,29 @@ void imd_format::fixnum(char *start, char *end) const }; } -int imd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int imd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { char h[4]; - io_generic_read(io, h, 0, 4); + size_t actual; + io.read_at(0, h, 4, actual); if(!memcmp(h, "IMD ", 4)) return 100; return 0; } -bool imd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool imd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); uint64_t pos, savepos; - for(pos=0; pos < size && img[pos] != 0x1a; pos++) {}; + for(pos=0; pos < size && img[pos] != 0x1a; pos++) { } pos++; m_comment.resize(pos); @@ -627,39 +632,34 @@ bool can_compress(const uint8_t* buffer, uint8_t ptrn, uint64_t size) return true; } -bool imd_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool imd_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t pos = 0; - io_generic_write(io, &m_comment[0], pos, m_comment.size()); - pos += m_comment.size(); + if(io.seek(0, SEEK_SET)) + return false; + + size_t written; + io.write(&m_comment[0], m_comment.size(), written); for (int i = 0; i < m_mode.size(); i++) { - io_generic_write(io, &m_mode[i], pos++, 1); - io_generic_write(io, &m_track[i], pos++, 1); - io_generic_write(io, &m_head[i], pos++, 1); - io_generic_write(io, &m_sector_count[i], pos++, 1); - io_generic_write(io, &m_ssize[i], pos++, 1); + io.write(&m_mode[i], 1, written); + io.write(&m_track[i], 1, written); + io.write(&m_head[i], 1, written); + io.write(&m_sector_count[i], 1, written); + io.write(&m_ssize[i], 1, written); - io_generic_write(io, &m_snum[i][0], pos, m_sector_count[i]); - pos += m_sector_count[i]; + io.write(&m_snum[i][0], m_sector_count[i], written); if (m_tnum[i].size()) - { - io_generic_write(io, &m_tnum[i][0], pos, m_sector_count[i]); - pos += m_sector_count[i]; - } + io.write(&m_tnum[i][0], m_sector_count[i], written); if (m_hnum[i].size()) - { - io_generic_write(io, &m_hnum[i][0], pos, m_sector_count[i]); - pos += m_sector_count[i]; - } + io.write(&m_hnum[i][0], m_sector_count[i], written); - uint32_t actual_size = m_ssize[i] < 7 ? 128 << m_ssize[i] : 8192; - uint8_t head = m_head[i] & 0x3f; + uint32_t const actual_size = m_ssize[i] < 7 ? 128 << m_ssize[i] : 8192; + uint8_t const head = m_head[i] & 0x3f; - bool fm = m_mode[i]< 3; + bool const fm = m_mode[i]< 3; auto bitstream = generate_bitstream_from_track(m_track[i]*m_trackmult, head, fm ? 4000 : 2000, image); std::vector<std::vector<uint8_t>> sectors; @@ -674,11 +674,10 @@ bool imd_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo const auto &data = sectors[m_snum[i][j]]; - uint8_t mode; if (data.empty()) { - mode = 0; - io_generic_write(io, &mode, pos++, 1); + uint8_t const mode = 0; + io.write(&mode, 1, written); continue; } else if (data.size() < actual_size) { @@ -690,16 +689,15 @@ bool imd_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo if (can_compress(sdata, sdata[0], actual_size)) { - mode = 2; - io_generic_write(io, &mode, pos++, 1); - io_generic_write(io, &sdata[0], pos++, 1); + uint8_t const mode = 2; + io.write(&mode, 1, written); + io.write(&sdata[0], 1, written); } else { - mode = 1; - io_generic_write(io, &mode, pos++, 1); - io_generic_write(io, &sdata, pos, actual_size); - pos += actual_size; + uint8_t const mode = 1; + io.write(&mode, 1, written); + io.write(&sdata, actual_size, written); } } } diff --git a/src/lib/formats/imd_dsk.h b/src/lib/formats/imd_dsk.h index ba04a0c09e7..acf7da9b892 100644 --- a/src/lib/formats/imd_dsk.h +++ b/src/lib/formats/imd_dsk.h @@ -17,9 +17,9 @@ class imd_format : public floppy_image_format_t public: imd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image* image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image* image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/img_dsk.cpp b/src/lib/formats/img_dsk.cpp index 757f695d923..73ae499c764 100644 --- a/src/lib/formats/img_dsk.cpp +++ b/src/lib/formats/img_dsk.cpp @@ -17,6 +17,7 @@ #include "img_dsk.h" #include "coretmpl.h" // BIT +#include "ioprocs.h" // Debugging @@ -40,9 +41,12 @@ img_format::img_format() { } -int img_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int img_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) { + return 0; + } if (((form_factor == floppy_image::FF_8) || (form_factor == floppy_image::FF_UNKNOWN)) && size == IMG_IMAGE_SIZE) { @@ -52,17 +56,18 @@ int img_format::identify(io_generic *io, uint32_t form_factor, const std::vector } } -bool img_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); - if (size != IMG_IMAGE_SIZE) { + uint64_t size; + if (io.length(size) || (size != IMG_IMAGE_SIZE)) { return false; } image->set_variant(floppy_image::SSDD); // Suck in the whole image std::vector<uint8_t> image_data(size); - io_generic_read(io, (void *)image_data.data(), 0, size); + size_t actual; + io.read_at(0, image_data.data(), size, actual); for (unsigned cyl = 0; cyl < TRACKS; cyl++) { std::vector<uint32_t> track_data; @@ -96,7 +101,7 @@ bool img_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool img_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool img_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { for (int cyl = 0; cyl < TRACKS; cyl++) { auto bitstream = generate_bitstream_from_track(cyl , 0 , CELL_SIZE , image , 0); @@ -106,7 +111,8 @@ bool img_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo while (get_next_sector(bitstream , pos , track_no , sector_no , sector_data)) { if (track_no == cyl && sector_no >= 1 && sector_no <= SECTORS) { unsigned offset_in_image = (cyl * SECTORS + sector_no - 1) * SECTOR_SIZE; - io_generic_write(io, sector_data, offset_in_image, SECTOR_SIZE); + size_t actual; + io.write_at(offset_in_image, sector_data, SECTOR_SIZE, actual); } } } diff --git a/src/lib/formats/img_dsk.h b/src/lib/formats/img_dsk.h index af9a2d62466..bbd7a0fc03e 100644 --- a/src/lib/formats/img_dsk.h +++ b/src/lib/formats/img_dsk.h @@ -27,9 +27,9 @@ public: img_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; diff --git a/src/lib/formats/ioprocs.cpp b/src/lib/formats/ioprocs.cpp deleted file mode 100644 index 78e009aa112..00000000000 --- a/src/lib/formats/ioprocs.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -#include <cstdio> -#include <cstring> -#include <cassert> -#include "ioprocs.h" -#include "corefile.h" - - -/********************************************************************* - ioprocs implementation on stdio -*********************************************************************/ - -static void stdio_closeproc(void *file) -{ - fclose((FILE*)file); -} - -static int stdio_seekproc(void *file, int64_t offset, int whence) -{ - return fseek((FILE*)file, (long) offset, whence); -} - -static size_t stdio_readproc(void *file, void *buffer, size_t length) -{ - return fread(buffer, 1, length, (FILE*)file); -} - -static size_t stdio_writeproc(void *file, const void *buffer, size_t length) -{ - return fwrite(buffer, 1, length, (FILE*)file); -} - -static uint64_t stdio_filesizeproc(void *file) -{ - long l, sz; - l = ftell((FILE*)file); - if (fseek((FILE*)file, 0, SEEK_END)) - return (size_t) -1; - sz = ftell((FILE*)file); - if (fseek((FILE*)file, l, SEEK_SET)) - return (size_t) -1; - return (size_t) sz; -} - -const struct io_procs stdio_ioprocs = -{ - stdio_closeproc, - stdio_seekproc, - stdio_readproc, - stdio_writeproc, - stdio_filesizeproc -}; - -const struct io_procs stdio_ioprocs_noclose = -{ - nullptr, - stdio_seekproc, - stdio_readproc, - stdio_writeproc, - stdio_filesizeproc -}; - -/********************************************************************* - ioprocs implementation on corefile -*********************************************************************/ - -static void corefile_closeproc(void *file) -{ - delete (util::core_file*)file; -} - -static int corefile_seekproc(void *file, int64_t offset, int whence) -{ - return ((util::core_file*)file)->seek(offset, whence); -} - -static size_t corefile_readproc(void *file, void *buffer, size_t length) -{ - return ((util::core_file*)file)->read(buffer, length); -} - -static size_t corefile_writeproc(void *file, const void *buffer, size_t length) -{ - return ((util::core_file*)file)->write(buffer, length); -} - -static uint64_t corefile_filesizeproc(void *file) -{ - const auto l = ((util::core_file*)file)->tell(); - if (((util::core_file*)file)->seek(0, SEEK_END)) - return (size_t) -1; - const auto sz = ((util::core_file*)file)->tell(); - if (((util::core_file*)file)->seek(l, SEEK_SET)) - return uint64_t(-1); - return uint64_t(sz); -} - -const struct io_procs corefile_ioprocs = -{ - corefile_closeproc, - corefile_seekproc, - corefile_readproc, - corefile_writeproc, - corefile_filesizeproc -}; - -const struct io_procs corefile_ioprocs_noclose = -{ - nullptr, - corefile_seekproc, - corefile_readproc, - corefile_writeproc, - corefile_filesizeproc -}; - - - -/********************************************************************* - calls for accessing generic IO -*********************************************************************/ - -static void io_generic_seek(struct io_generic *genio, uint64_t offset) -{ - genio->procs->seekproc(genio->file, offset, SEEK_SET); -} - - - -void io_generic_close(struct io_generic *genio) -{ - if (genio->procs->closeproc) - genio->procs->closeproc(genio->file); -} - - - -void io_generic_read(struct io_generic *genio, void *buffer, uint64_t offset, size_t length) -{ - uint64_t size; - size_t bytes_read; - - size = io_generic_size(genio); - if (size <= offset) - { - bytes_read = 0; - } - else - { - io_generic_seek(genio, offset); - bytes_read = genio->procs->readproc(genio->file, buffer, length); - } - memset(((uint8_t *) buffer) + bytes_read, genio->filler, length - bytes_read); -} - - - -void io_generic_write(struct io_generic *genio, const void *buffer, uint64_t offset, size_t length) -{ - uint64_t filler_size = 0; - char filler_buffer[1024]; - size_t bytes_to_write; - uint64_t size; - - size = io_generic_size(genio); - - if (size < offset) - { - filler_size = offset - size; - offset = size; - } - - io_generic_seek(genio, offset); - - if (filler_size) - { - memset(filler_buffer, genio->filler, sizeof(filler_buffer)); - do - { - bytes_to_write = (filler_size > sizeof(filler_buffer)) ? sizeof(filler_buffer) : (size_t) filler_size; - genio->procs->writeproc(genio->file, filler_buffer, bytes_to_write); - filler_size -= bytes_to_write; - } - while(filler_size > 0); - } - - if (length > 0) - genio->procs->writeproc(genio->file, buffer, length); -} - - - -void io_generic_write_filler(struct io_generic *genio, uint8_t filler, uint64_t offset, size_t length) -{ - uint8_t buffer[512]; - size_t this_length; - - memset(buffer, filler, std::min(length, sizeof(buffer))); - - while(length > 0) - { - this_length = std::min(length, sizeof(buffer)); - io_generic_write(genio, buffer, offset, this_length); - offset += this_length; - length -= this_length; - } -} - - - -uint64_t io_generic_size(struct io_generic *genio) -{ - return genio->procs->filesizeproc(genio->file); -} diff --git a/src/lib/formats/ioprocs.h b/src/lib/formats/ioprocs.h deleted file mode 100644 index 1244873f14c..00000000000 --- a/src/lib/formats/ioprocs.h +++ /dev/null @@ -1,70 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Nathan Woods -/********************************************************************* - - ioprocs.h - - File IO abstraction layer - -*********************************************************************/ -#ifndef MAME_FORMATS_IOPROCS_H -#define MAME_FORMATS_IOPROCS_H - -#pragma once - -#include <cstdint> -#include <cstdlib> - - - -/*************************************************************************** - - Type definitions - -***************************************************************************/ - -struct io_procs -{ - void (*closeproc)(void *file) = nullptr; - int (*seekproc)(void *file, int64_t offset, int whence) = nullptr; - size_t (*readproc)(void *file, void *buffer, size_t length) = nullptr; - size_t (*writeproc)(void *file, const void *buffer, size_t length) = nullptr; - uint64_t (*filesizeproc)(void *file) = nullptr; -}; - - - -struct io_generic -{ - const struct io_procs *procs = nullptr; - void *file = nullptr; - uint8_t filler = 0; -}; - - -/*************************************************************************** - - Globals - -***************************************************************************/ - -extern const io_procs stdio_ioprocs; -extern const io_procs stdio_ioprocs_noclose; -extern const io_procs corefile_ioprocs; -extern const io_procs corefile_ioprocs_noclose; - - - -/*************************************************************************** - - Prototypes - -***************************************************************************/ - -void io_generic_close(struct io_generic *genio); -void io_generic_read(struct io_generic *genio, void *buffer, uint64_t offset, size_t length); -void io_generic_write(struct io_generic *genio, const void *buffer, uint64_t offset, size_t length); -void io_generic_write_filler(struct io_generic *genio, uint8_t filler, uint64_t offset, size_t length); -uint64_t io_generic_size(struct io_generic *genio); - -#endif // MAME_FORMATS_IOPROCS_H diff --git a/src/lib/formats/ipf_dsk.cpp b/src/lib/formats/ipf_dsk.cpp index 0f1725f5c14..10c9ba2c4a9 100644 --- a/src/lib/formats/ipf_dsk.cpp +++ b/src/lib/formats/ipf_dsk.cpp @@ -2,6 +2,8 @@ // copyright-holders:Olivier Galibert #include "ipf_dsk.h" +#include "ioprocs.h" + #include <cassert> @@ -27,11 +29,12 @@ bool ipf_format::supports_save() const return false; } -int ipf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ipf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { static const uint8_t refh[12] = { 0x43, 0x41, 0x50, 0x53, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0xd5, 0x73, 0xba }; uint8_t h[12]; - io_generic_read(io, h, 0, 12); + size_t actual; + io.read_at(0, h, 12, actual); if(!memcmp(h, refh, 12)) return 100; @@ -39,14 +42,16 @@ int ipf_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool ipf_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool ipf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - ipf_decode dec; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; std::vector<uint8_t> data(size); - io_generic_read(io, &data[0], 0, size); - bool res = dec.parse(data, image); - return res; + size_t actual; + io.read_at(0, &data[0], size, actual); + ipf_decode dec; + return dec.parse(data, image); } uint32_t ipf_format::ipf_decode::r32(const uint8_t *p) diff --git a/src/lib/formats/ipf_dsk.h b/src/lib/formats/ipf_dsk.h index d848a5bb3a0..28d552d5812 100644 --- a/src/lib/formats/ipf_dsk.h +++ b/src/lib/formats/ipf_dsk.h @@ -12,8 +12,8 @@ class ipf_format : public floppy_image_format_t { public: - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/jfd_dsk.cpp b/src/lib/formats/jfd_dsk.cpp index 947d6ba4022..7a1da472356 100644 --- a/src/lib/formats/jfd_dsk.cpp +++ b/src/lib/formats/jfd_dsk.cpp @@ -158,9 +158,13 @@ *********************************************************************/ -#include <zlib.h> #include "formats/jfd_dsk.h" +#include "ioprocs.h" + +#include <zlib.h> + + static const uint8_t JFD_HEADER[4] = { 'J', 'F', 'D', 'I' }; static const uint8_t GZ_HEADER[2] = { 0x1f, 0x8b }; @@ -183,11 +187,14 @@ const char *jfd_format::extensions() const return "jfd"; } -int jfd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int jfd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); int err; std::vector<uint8_t> gz_ptr(4); @@ -221,11 +228,15 @@ int jfd_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool jfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool jfd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; + std::vector<uint8_t> img(size); - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); int err; std::vector<uint8_t> gz_ptr; diff --git a/src/lib/formats/jfd_dsk.h b/src/lib/formats/jfd_dsk.h index 75b9910c426..7231ccf3460 100644 --- a/src/lib/formats/jfd_dsk.h +++ b/src/lib/formats/jfd_dsk.h @@ -23,8 +23,8 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; }; diff --git a/src/lib/formats/jvc_dsk.cpp b/src/lib/formats/jvc_dsk.cpp index 8332f86bace..c71f2c3be06 100644 --- a/src/lib/formats/jvc_dsk.cpp +++ b/src/lib/formats/jvc_dsk.cpp @@ -106,6 +106,8 @@ #include "jvc_dsk.h" +#include "ioprocs.h" + jvc_format::jvc_format() { @@ -126,19 +128,22 @@ const char *jvc_format::extensions() const return "jvc,dsk"; } -bool jvc_format::parse_header(io_generic *io, int &header_size, int &tracks, int &heads, int §ors, int §or_size, int &base_sector_id) +bool jvc_format::parse_header(util::random_read &io, int &header_size, int &tracks, int &heads, int §ors, int §or_size, int &base_sector_id) { // The JVC format has a header whose size is the size of the image modulo 256. Currently, we only // handle up to five header bytes - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return false; header_size = size % 256; uint8_t header[5]; // if we know that this is a header of a bad size, we can fail immediately; otherwise read the header + size_t actual; if (header_size >= sizeof(header)) return false; if (header_size > 0) - io_generic_read(io, header, 0, header_size); + io.read_at(0, header, header_size, actual); // default values heads = 1; @@ -168,13 +173,13 @@ bool jvc_format::parse_header(io_generic *io, int &header_size, int &tracks, int return tracks * heads * sectors * sector_size == (size - header_size); } -int jvc_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int jvc_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int header_size, tracks, heads, sectors, sector_size, sector_base_id; return parse_header(io, header_size, tracks, heads, sectors, sector_size, sector_base_id) ? 50 : 0; } -bool jvc_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool jvc_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int header_size, track_count, head_count, sector_count, sector_size, sector_base_id; @@ -210,7 +215,8 @@ bool jvc_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui sectors[interleave[i]].bad_crc = false; sectors[interleave[i]].data = §or_data[sector_offset]; - io_generic_read(io, sectors[interleave[i]].data, file_offset, sector_size); + size_t actual; + io.read_at(file_offset, sectors[interleave[i]].data, sector_size, actual); sector_offset += sector_size; file_offset += sector_size; @@ -223,7 +229,7 @@ bool jvc_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool jvc_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool jvc_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { uint64_t file_offset = 0; @@ -236,7 +242,8 @@ bool jvc_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo uint8_t header[2]; header[0] = 18; header[1] = 2; - io_generic_write(io, header, file_offset, sizeof(header)); + size_t actual; + io.write_at(file_offset, header, sizeof(header), actual); file_offset += sizeof(header); } @@ -256,7 +263,8 @@ bool jvc_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo return false; } - io_generic_write(io, sectors[1 + i].data(), file_offset, 256); + size_t actual; + io.write_at(file_offset, sectors[1 + i].data(), 256, actual); file_offset += 256; } } diff --git a/src/lib/formats/jvc_dsk.h b/src/lib/formats/jvc_dsk.h index 7c744a0acb5..1b8b59c725f 100644 --- a/src/lib/formats/jvc_dsk.h +++ b/src/lib/formats/jvc_dsk.h @@ -35,13 +35,13 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; private: - bool parse_header(io_generic *io, int &header_size, int &tracks, int &heads, int §ors, int §or_size, int &base_sector_id); + bool parse_header(util::random_read &io, int &header_size, int &tracks, int &heads, int §ors, int §or_size, int &base_sector_id); }; extern const floppy_format_type FLOPPY_JVC_FORMAT; diff --git a/src/lib/formats/m20_dsk.cpp b/src/lib/formats/m20_dsk.cpp index 60b2ae58176..05c52c2f211 100644 --- a/src/lib/formats/m20_dsk.cpp +++ b/src/lib/formats/m20_dsk.cpp @@ -16,6 +16,9 @@ #include "m20_dsk.h" +#include "ioprocs.h" + + m20_format::m20_format() { } @@ -40,21 +43,27 @@ bool m20_format::supports_save() const return true; } -int m20_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int m20_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - if(io_generic_size(io) == 286720) + uint64_t size; + if (io.length(size)) + return 0; + + if (size == 286720) return 50; + return 0; } -bool m20_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool m20_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { for (int track = 0; track < 35; track++) for (int head = 0; head < 2; head ++) { bool mfm = track || head; desc_pc_sector sects[16]; uint8_t sectdata[16*256]; - io_generic_read(io, sectdata, 16*256*(track*2+head), 16*256); + size_t actual; + io.read_at(16*256*(track*2+head), sectdata, 16*256, actual); for (int i = 0; i < 16; i++) { int j = i/2 + (i & 1 ? 0 : 8); sects[i].track = track; @@ -76,7 +85,7 @@ bool m20_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool m20_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool m20_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { uint64_t file_offset = 0; @@ -87,26 +96,27 @@ bool m20_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo auto bitstream = generate_bitstream_from_track(0, 0, 4000, image); auto sectors = extract_sectors_from_bitstream_fm_pc(bitstream); - for (int i = 0; i < 16; i++) - { - io_generic_write(io, sectors[i + 1].data(), file_offset, 128); + for (int i = 0; i < 16; i++) { + size_t actual; + io.write_at(file_offset, sectors[i + 1].data(), 128, actual); file_offset += 256; //128; } // rest are mfm tracks - for (int track = 0; track < track_count; track++) - { - for (int head = 0; head < head_count; head++) - { + for (int track = 0; track < track_count; track++) { + for (int head = 0; head < head_count; head++) { // skip track 0, head 0 - if (track == 0) { if (head_count == 1) break; else head++; } + if (track == 0) { + if (head_count == 1) break; + else head++; + } bitstream = generate_bitstream_from_track(track, head, 2000, image); sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); - for (int i = 0; i < 16; i++) - { - io_generic_write(io, sectors[i + 1].data(), file_offset, 256); + for (int i = 0; i < 16; i++) { + size_t actual; + io.write_at(file_offset, sectors[i + 1].data(), 256, actual); file_offset += 256; } } diff --git a/src/lib/formats/m20_dsk.h b/src/lib/formats/m20_dsk.h index ed8a7bc4517..d9bd7a45425 100644 --- a/src/lib/formats/m20_dsk.h +++ b/src/lib/formats/m20_dsk.h @@ -18,9 +18,9 @@ class m20_format : public floppy_image_format_t { public: m20_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/mdos_dsk.cpp b/src/lib/formats/mdos_dsk.cpp index b96be2f327e..e49d825ea9a 100644 --- a/src/lib/formats/mdos_dsk.cpp +++ b/src/lib/formats/mdos_dsk.cpp @@ -50,7 +50,9 @@ */ #include "mdos_dsk.h" -#include "formats/imageutl.h" +#include "imageutl.h" + +#include "ioprocs.h" mdos_format::mdos_format() : wd177x_format(formats) @@ -72,12 +74,13 @@ const char *mdos_format::extensions() const return "dsk"; } -int mdos_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int mdos_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor, variants); + int type = find_size(io, form_factor, variants); if (type != -1) return 75; + return 0; } @@ -109,12 +112,15 @@ int mdos_format::parse_date_field(uint8_t *str) return (high - 0x30) * 10 + (low - 0x30); } -int mdos_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int mdos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + size_t actual; + uint64_t size; + if (io.length(size)) + return -1; // Look at the disk id sector. - io_generic_read(io, &info, 0, sizeof(struct disk_id_sector)); + io.read_at(0, &info, sizeof(struct disk_id_sector), actual); LOG_FORMATS("MDOS floppy dsk: size %d bytes, %d total sectors, %d remaining bytes, expected form factor %x\n", (uint32_t)size, (uint32_t)size / 128, (uint32_t)size % 128, form_factor); @@ -176,8 +182,8 @@ int mdos_format::find_size(io_generic *io, uint32_t form_factor, const std::vect // the extent of the disk are free or available. uint8_t cluster_allocation[128], cluster_available[128]; - io_generic_read(io, &cluster_allocation, 1 * 128, sizeof(cluster_allocation)); - io_generic_read(io, &cluster_available, 2 * 128, sizeof(cluster_available)); + io.read_at(1 * 128, &cluster_allocation, sizeof(cluster_allocation), actual); + io.read_at(2 * 128, &cluster_available, sizeof(cluster_available), actual); for (int cluster = 0; cluster < sizeof(cluster_allocation) * 8; cluster++) { if (cluster * 4 * 128 + 4 * 128 > size) { diff --git a/src/lib/formats/mdos_dsk.h b/src/lib/formats/mdos_dsk.h index 65e7bca9f14..56dd29c9954 100644 --- a/src/lib/formats/mdos_dsk.h +++ b/src/lib/formats/mdos_dsk.h @@ -19,8 +19,8 @@ public: virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual const wd177x_format::format &get_track_format(const format &f, int head, int track) override; private: diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index 7670bf6bfb9..8272253c36a 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -1,10 +1,12 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert -#include <cassert> - #include "mfi_dsk.h" + +#include "ioprocs.h" + #include <zlib.h> + /* Mess floppy image structure: @@ -94,11 +96,12 @@ bool mfi_format::supports_save() const return true; } -int mfi_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int mfi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { header h; - io_generic_read(io, &h, 0, sizeof(header)); + size_t actual; + io.read_at(0, &h, sizeof(header), actual); if(memcmp( h.sign, sign, 16 ) == 0 && (h.cyl_count & CYLINDER_MASK) <= 84 && (h.cyl_count >> RESOLUTION_SHIFT) < 3 && @@ -108,15 +111,16 @@ int mfi_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; header h; entry entries[84*2*4]; - io_generic_read(io, &h, 0, sizeof(header)); + io.read_at(0, &h, sizeof(header), actual); int resolution = h.cyl_count >> RESOLUTION_SHIFT; h.cyl_count &= CYLINDER_MASK; - io_generic_read(io, &entries, sizeof(header), (h.cyl_count << resolution)*h.head_count*sizeof(entry)); + io.read_at(sizeof(header), &entries, (h.cyl_count << resolution)*h.head_count*sizeof(entry), actual); image->set_form_variant(h.form_factor, h.variant); @@ -139,7 +143,7 @@ bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui compressed.resize(ent->compressed_size); - io_generic_read(io, &compressed[0], ent->offset, ent->compressed_size); + io.read_at(ent->offset, &compressed[0], ent->compressed_size, actual); unsigned int cell_count = ent->uncompressed_size/4; std::vector<uint32_t> &trackbuf = image->get_buffer(cyl >> 2, head, cyl & 3);; @@ -169,8 +173,9 @@ bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; int tracks, heads; image->get_actual_geometry(tracks, heads); int resolution = image->get_resolution(); @@ -190,7 +195,7 @@ bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo h.form_factor = image->get_form_factor(); h.variant = image->get_variant(); - io_generic_write(io, &h, 0, sizeof(header)); + io.write_at(0, &h, sizeof(header), actual); memset(entries, 0, sizeof(entries)); @@ -226,11 +231,11 @@ bool mfi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo entries[epos].write_splice = image->get_write_splice_position(track >> 2, head, track & 3); epos++; - io_generic_write(io, postcomp.get(), pos, csize); + io.write_at(pos, postcomp.get(), csize, actual); pos += csize; } - io_generic_write(io, entries, sizeof(header), (tracks << resolution)*heads*sizeof(entry)); + io.write_at(sizeof(header), entries, (tracks << resolution)*heads*sizeof(entry), actual); return true; } diff --git a/src/lib/formats/mfi_dsk.h b/src/lib/formats/mfi_dsk.h index 129a9ee599e..d0dd36c3d68 100644 --- a/src/lib/formats/mfi_dsk.h +++ b/src/lib/formats/mfi_dsk.h @@ -12,9 +12,9 @@ class mfi_format : public floppy_image_format_t public: mfi_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/mfm_hd.cpp b/src/lib/formats/mfm_hd.cpp index 98d8079443c..738f0999863 100644 --- a/src/lib/formats/mfm_hd.cpp +++ b/src/lib/formats/mfm_hd.cpp @@ -294,9 +294,9 @@ int mfmhd_generic_format::chs_to_lba(int cylinder, int head, int sector) else return -1; } -chd_error mfmhd_generic_format::load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) +std::error_condition mfmhd_generic_format::load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) { - chd_error state = CHDERR_NONE; + std::error_condition state; uint8_t sector_content[16384]; int sectorcount = m_param.sectors_per_track; @@ -382,8 +382,9 @@ chd_error mfmhd_generic_format::load(chd_file* chdfile, uint16_t* trackimage, in int lbaposition = chs_to_lba(cylinder, head, sec_number); if (lbaposition>=0) { - chd_error state = chdfile->read_units(lbaposition, sector_content); - if (state != CHDERR_NONE) break; + state = chdfile->read_units(lbaposition, sector_content); + if (state) + break; } else { @@ -413,7 +414,7 @@ chd_error mfmhd_generic_format::load(chd_file* chdfile, uint16_t* trackimage, in if (TRACE_LAYOUT) osd_printf_verbose("\n"); // Gap 4 - if (state == CHDERR_NONE) + if (!state) { // Fill the rest with 0x4e mfm_encode(trackimage, position, 0x4e, tracksize-position); @@ -433,7 +434,7 @@ enum CHECK_CRC }; -chd_error mfmhd_generic_format::save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int current_cylinder, int current_head) +std::error_condition mfmhd_generic_format::save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int current_cylinder, int current_head) { if (TRACE_RWTRACK) osd_printf_verbose("%s: write back (c=%d,h=%d) to CHD\n", tag(), current_cylinder, current_head); @@ -490,7 +491,7 @@ chd_error mfmhd_generic_format::save(chd_file* chdfile, uint16_t* trackimage, in bool countgap3 = false; bool countsync = false; - chd_error chdstate = CHDERR_NONE; + std::error_condition chdstate; if (TRACE_IMAGE) { @@ -643,7 +644,7 @@ chd_error mfmhd_generic_format::save(chd_file* chdfile, uint16_t* trackimage, in if (TRACE_DETAIL) osd_printf_verbose("%s: Writing sector chs=(%d,%d,%d) to CHD\n", tag(), current_cylinder, current_head, sector); chdstate = chdfile->write_units(chs_to_lba(current_cylinder, current_head, sector), buffer); - if (chdstate != CHDERR_NONE) + if (chdstate) { osd_printf_verbose("%s: Write error while writing sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector); } diff --git a/src/lib/formats/mfm_hd.h b/src/lib/formats/mfm_hd.h index 7d28adc518d..472062d1440 100644 --- a/src/lib/formats/mfm_hd.h +++ b/src/lib/formats/mfm_hd.h @@ -151,10 +151,10 @@ public: virtual ~mfmhd_image_format_t() {}; // Load the image. - virtual chd_error load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0; + virtual std::error_condition load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0; // Save the image. - virtual chd_error save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0; + virtual std::error_condition save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) = 0; // Return the original parameters of the image mfmhd_layout_params* get_initial_params() { return &m_param_old; } @@ -196,8 +196,8 @@ class mfmhd_generic_format : public mfmhd_image_format_t { public: mfmhd_generic_format() { m_devtag = std::string("mfmhd_generic_format"); }; - chd_error load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override; - chd_error save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override; + std::error_condition load(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override; + std::error_condition save(chd_file* chdfile, uint16_t* trackimage, int tracksize, int cylinder, int head) override; // Yes, we want to save all parameters virtual bool save_param(mfmhd_param_t type) override { return true; } diff --git a/src/lib/formats/nfd_dsk.cpp b/src/lib/formats/nfd_dsk.cpp index 1a0430f9af1..4a51e0db54c 100644 --- a/src/lib/formats/nfd_dsk.cpp +++ b/src/lib/formats/nfd_dsk.cpp @@ -77,10 +77,11 @@ *********************************************************************/ - #include <cassert> - #include "nfd_dsk.h" +#include "ioprocs.h" + + nfd_format::nfd_format() { } @@ -100,10 +101,11 @@ const char *nfd_format::extensions() const return "nfd"; } -int nfd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int nfd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[16]; - io_generic_read(io, h, 0, 16); + size_t actual; + io.read_at(0, h, 16, actual); if (strncmp((const char *)h, "T98FDDIMAGE.R0", 14) == 0 || strncmp((const char *)h, "T98FDDIMAGE.R1", 14) == 0) return 100; @@ -111,11 +113,14 @@ int nfd_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); + size_t actual; + uint64_t size; + if (io.length(size)) + return false; uint8_t h[0x120], hsec[0x10]; - io_generic_read(io, h, 0, 0x120); + io.read_at(0, h, 0x120, actual); int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; // sector map (the 164th entry is only used by rev.1 format, loops with track < 163 are correct for rev.0) @@ -140,7 +145,7 @@ bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui { int curr_track_size = 0; // read sector map absolute location - io_generic_read(io, hsec, pos, 4); + io.read_at(pos, hsec, 4, actual); pos += 4; uint32_t secmap_addr = little_endianize_int32(*(uint32_t *)(hsec)); @@ -149,14 +154,14 @@ bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui // read actual sector map for the sectors of this track // for rev.1 format the first 0x10 are a track summary: // first WORD is # of sectors, second WORD is # of special data sectors - io_generic_read(io, hsec, secmap_addr, 0x10); + io.read_at(secmap_addr, hsec, 0x10, actual); secmap_addr += 0x10; num_secs[track] = little_endianize_int16(*(uint16_t *)(hsec)); num_specials[track] = little_endianize_int16(*(uint16_t *)(hsec + 0x2)); for (int sect = 0; sect < num_secs[track]; sect++) { - io_generic_read(io, hsec, secmap_addr, 0x10); + io.read_at(secmap_addr, hsec, 0x10, actual); if (track == 0 && sect == 0) disk_type = hsec[0xb]; // can this change across the disk? I don't think so... @@ -175,7 +180,7 @@ bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui { for (int sect = 0; sect < num_specials[track]; sect++) { - io_generic_read(io, hsec, secmap_addr, 0x10); + io.read_at(secmap_addr, hsec, 0x10, actual); secmap_addr += 0x10; curr_track_size += (hsec[9] + 1) * little_endianize_int32(*(uint32_t *)(hsec + 0x0a)); } @@ -198,7 +203,7 @@ bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui { // read sector map for this sector // for rev.0 format each sector uses 0x10 bytes - io_generic_read(io, hsec, pos, 0x10); + io.read_at(pos, hsec, 0x10, actual); if (track == 0 && sect == 0) disk_type = hsec[0xa]; // can this change across the disk? I don't think so... @@ -245,7 +250,7 @@ bool nfd_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for (int track = 0; track < 163 && pos < size; track++) { - io_generic_read(io, sect_data, pos, track_sizes[track]); + io.read_at(pos, sect_data, track_sizes[track], actual); for (int i = 0; i < num_secs[track]; i++) { diff --git a/src/lib/formats/nfd_dsk.h b/src/lib/formats/nfd_dsk.h index 5eb41893c5f..c0030b073a5 100644 --- a/src/lib/formats/nfd_dsk.h +++ b/src/lib/formats/nfd_dsk.h @@ -20,8 +20,8 @@ class nfd_format : public floppy_image_format_t public: nfd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/opd_dsk.cpp b/src/lib/formats/opd_dsk.cpp index e105d53d678..964b30b75a0 100644 --- a/src/lib/formats/opd_dsk.cpp +++ b/src/lib/formats/opd_dsk.cpp @@ -30,12 +30,13 @@ const char *opd_format::extensions() const return "opd,opu"; } -int opd_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int opd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if (type != -1) return 90; + return 0; } diff --git a/src/lib/formats/opd_dsk.h b/src/lib/formats/opd_dsk.h index 9a4205314ec..9236320f154 100644 --- a/src/lib/formats/opd_dsk.h +++ b/src/lib/formats/opd_dsk.h @@ -21,7 +21,7 @@ class opd_format : public wd177x_format public: opd_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual int get_image_offset(const format &f, int head, int track) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/oric_dsk.cpp b/src/lib/formats/oric_dsk.cpp index 22d70124572..f5b0783a112 100644 --- a/src/lib/formats/oric_dsk.cpp +++ b/src/lib/formats/oric_dsk.cpp @@ -8,7 +8,9 @@ *********************************************************************/ -#include "formats/oric_dsk.h" +#include "oric_dsk.h" + +#include "ioprocs.h" const char *oric_dsk_format::name() const @@ -31,10 +33,11 @@ bool oric_dsk_format::supports_save() const return true; } -int oric_dsk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int oric_dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[256]; - io_generic_read(io, h, 0, 256); + size_t actual; + io.read_at(0, h, 256, actual); if(memcmp(h, "MFM_DISK", 8)) return 0; @@ -43,27 +46,30 @@ int oric_dsk_format::identify(io_generic *io, uint32_t form_factor, const std::v int tracks = (h[15] << 24) | (h[14] << 16) | (h[13] << 8) | h[12]; int geom = (h[19] << 24) | (h[18] << 16) | (h[17] << 8) | h[16]; - int size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; if(sides < 0 || sides > 2 || geom != 1 || size != 256+6400*sides*tracks) return 0; return 100; } -bool oric_dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool oric_dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t h[256]; uint8_t t[6250+3]; t[6250] = t[6251] = t[6252] = 0; - io_generic_read(io, h, 0, 256); + io.read_at(0, h, 256, actual); int sides = (h[11] << 24) | (h[10] << 16) | (h[ 9] << 8) | h[ 8]; int tracks = (h[15] << 24) | (h[14] << 16) | (h[13] << 8) | h[12]; for(int side=0; side<sides; side++) for(int track=0; track<tracks; track++) { - io_generic_read(io, t, 256+6400*(tracks*side + track), 6250); + io.read_at(256+6400*(tracks*side + track), t, 6250, actual); std::vector<uint32_t> stream; int sector_size = 128; for(int i=0; i<6250; i++) { @@ -99,8 +105,9 @@ bool oric_dsk_format::load(io_generic *io, uint32_t form_factor, const std::vect return true; } -bool oric_dsk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool oric_dsk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { + // FIXME: surely this should return false, since it does't actually save anything? return true; } @@ -127,28 +134,35 @@ bool oric_jasmin_format::supports_save() const return true; } -int oric_jasmin_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int oric_jasmin_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int size = io_generic_size(io); - bool can_ds = variants.empty() || has_variant(variants, floppy_image::DSDD); + uint64_t size; + if(io.length(size)) + return 0; + + bool const can_ds = variants.empty() || has_variant(variants, floppy_image::DSDD); if(size == 41*17*256 || (can_ds && size == 41*17*256*2)) return 50; return 0; } -bool oric_jasmin_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool oric_jasmin_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int size = io_generic_size(io); - bool can_ds = variants.empty() || has_variant(variants, floppy_image::DSDD); + uint64_t size; + if(io.length(size)) + return false; + + bool const can_ds = variants.empty() || has_variant(variants, floppy_image::DSDD); if(size != 41*17*256 && (!can_ds || size != 41*17*256*2)) return false; - int heads = size == 41*17*256 ? 1 : 2; + int const heads = size == 41*17*256 ? 1 : 2; std::vector<uint8_t> data(size); - io_generic_read(io, data.data(), 0, size); + size_t actual; + io.read_at(0, data.data(), size, actual); for(int head = 0; head != heads; head++) for(int track = 0; track != 41; track++) { @@ -173,7 +187,7 @@ bool oric_jasmin_format::load(io_generic *io, uint32_t form_factor, const std::v return true; } -bool oric_jasmin_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool oric_jasmin_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int tracks, heads; image->get_actual_geometry(tracks, heads); @@ -191,8 +205,9 @@ bool oric_jasmin_format::save(io_generic *io, const std::vector<uint32_t> &varia for(int track = 0; track != 41; track++) { auto sectors = extract_sectors_from_bitstream_mfm_pc(generate_bitstream_from_track(track, head, 2000, image)); for(unsigned int sector = 0; sector != 17; sector ++) { - const uint8_t *data = sector+1 < sectors.size() && !sectors[sector+1].empty() ? sectors[sector+1].data() : zero; - io_generic_write(io, data, 256 * (sector + track*17 + head*17*41), 256); + uint8_t const *const data = (sector+1 < sectors.size() && !sectors[sector+1].empty()) ? sectors[sector+1].data() : zero; + size_t actual; + io.write_at(256 * (sector + track*17 + head*17*41), data, 256, actual); } } return true; diff --git a/src/lib/formats/oric_dsk.h b/src/lib/formats/oric_dsk.h index e42b876e52f..6fd1021384b 100644 --- a/src/lib/formats/oric_dsk.h +++ b/src/lib/formats/oric_dsk.h @@ -18,9 +18,9 @@ class oric_dsk_format : public floppy_image_format_t { public: oric_dsk_format() = default; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -35,9 +35,9 @@ class oric_jasmin_format : public floppy_image_format_t public: oric_jasmin_format() = default; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/os9_dsk.cpp b/src/lib/formats/os9_dsk.cpp index b28e4f8d293..ba1b2427811 100644 --- a/src/lib/formats/os9_dsk.cpp +++ b/src/lib/formats/os9_dsk.cpp @@ -48,6 +48,7 @@ #include "imageutl.h" #include "coretmpl.h" // BIT +#include "ioprocs.h" os9_format::os9_format() : wd177x_format(formats) @@ -69,21 +70,25 @@ const char *os9_format::extensions() const return "dsk,os9"; } -int os9_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int os9_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if (type != -1) return 75; + return 0; } -int os9_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int os9_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return -1; uint8_t os9_header[0x60]; - io_generic_read(io, os9_header, 0, sizeof(os9_header)); + size_t actual; + io.read_at(0, os9_header, sizeof(os9_header), actual); int os9_total_sectors = pick_integer_be(os9_header, 0x00, 3); int os9_heads = util::BIT(os9_header[0x10], 0) ? 2 : 1; diff --git a/src/lib/formats/os9_dsk.h b/src/lib/formats/os9_dsk.h index 57dfbfc9ab5..124c019d155 100644 --- a/src/lib/formats/os9_dsk.h +++ b/src/lib/formats/os9_dsk.h @@ -21,8 +21,8 @@ public: virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual const wd177x_format::format &get_track_format(const format &f, int head, int track) override; private: diff --git a/src/lib/formats/pasti_dsk.cpp b/src/lib/formats/pasti_dsk.cpp index 0ab6dc2f064..1a418096cd3 100644 --- a/src/lib/formats/pasti_dsk.cpp +++ b/src/lib/formats/pasti_dsk.cpp @@ -2,6 +2,8 @@ // copyright-holders:Olivier Galibert #include "pasti_dsk.h" +#include "ioprocs.h" + // Pasti format supported using the documentation at // http://www.sarnau.info/atari:pasti_file_format @@ -36,10 +38,11 @@ bool pasti_format::supports_save() const return false; } -int pasti_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int pasti_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t h[16]; - io_generic_read(io, h, 0, 16); + size_t actual; + io.read_at(0, h, 16, actual); if(!memcmp(h, "RSY\0\3\0", 6) && (1 || (h[10] >= 80 && h[10] <= 82) || (h[10] >= 160 && h[10] <= 164))) @@ -58,10 +61,11 @@ static void hexdump(const uint8_t *d, int s) } } -bool pasti_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool pasti_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t fh[16]; - io_generic_read(io, fh, 0, 16); + io.read_at(0, fh, 16, actual); std::vector<uint8_t> raw_track; @@ -76,7 +80,7 @@ bool pasti_format::load(io_generic *io, uint32_t form_factor, const std::vector< for(int track=0; track < tracks; track++) { for(int head=0; head < heads; head++) { uint8_t th[16]; - io_generic_read(io, th, pos, 16); + io.read_at(pos, th, 16, actual); int entry_len = th[0] | (th[1] << 8) | (th[2] << 16) | (th[3] << 24); int fuzz_len = th[4] | (th[5] << 8) | (th[6] << 16) | (th[7] << 24); int sect = th[8] | (th[9] << 8); @@ -87,7 +91,7 @@ bool pasti_format::load(io_generic *io, uint32_t form_factor, const std::vector< raw_track.resize(entry_len-16); - io_generic_read(io, &raw_track[0], pos+16, entry_len-16); + io.read_at(pos+16, &raw_track[0], entry_len-16, actual); uint8_t *fuzz = fuzz_len ? &raw_track[16*sect] : nullptr; uint8_t *bdata = fuzz ? fuzz+fuzz_len : &raw_track[16*sect]; diff --git a/src/lib/formats/pasti_dsk.h b/src/lib/formats/pasti_dsk.h index b3fc869da4d..2575c12eeb4 100644 --- a/src/lib/formats/pasti_dsk.h +++ b/src/lib/formats/pasti_dsk.h @@ -12,8 +12,8 @@ class pasti_format : public floppy_image_format_t public: pasti_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/pc98fdi_dsk.cpp b/src/lib/formats/pc98fdi_dsk.cpp index 2d503acebe4..61fb8fb8fe3 100644 --- a/src/lib/formats/pc98fdi_dsk.cpp +++ b/src/lib/formats/pc98fdi_dsk.cpp @@ -8,9 +8,11 @@ *********************************************************************/ -#include <cassert> #include "pc98fdi_dsk.h" +#include "ioprocs.h" + + pc98fdi_format::pc98fdi_format() { } @@ -30,47 +32,53 @@ const char *pc98fdi_format::extensions() const return "fdi"; } -int pc98fdi_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int pc98fdi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); - uint8_t h[32]; + uint64_t size; + if(io.length(size)) + return 0; - io_generic_read(io, h, 0, 32); - uint32_t hsize = little_endianize_int32(*(uint32_t *) (h + 0x8)); - uint32_t psize = little_endianize_int32(*(uint32_t *) (h + 0xc)); - uint32_t ssize = little_endianize_int32(*(uint32_t *) (h + 0x10)); - uint32_t scnt = little_endianize_int32(*(uint32_t *) (h + 0x14)); - uint32_t sides = little_endianize_int32(*(uint32_t *) (h + 0x18)); - uint32_t ntrk = little_endianize_int32(*(uint32_t *) (h + 0x1c)); + uint8_t h[32]; + size_t actual; + io.read_at(0, h, 32, actual); + + uint32_t const hsize = little_endianize_int32(*(uint32_t *) (h + 0x8)); + uint32_t const psize = little_endianize_int32(*(uint32_t *) (h + 0xc)); + uint32_t const ssize = little_endianize_int32(*(uint32_t *) (h + 0x10)); + uint32_t const scnt = little_endianize_int32(*(uint32_t *) (h + 0x14)); + uint32_t const sides = little_endianize_int32(*(uint32_t *) (h + 0x18)); + uint32_t const ntrk = little_endianize_int32(*(uint32_t *) (h + 0x1c)); if(size == hsize + psize && psize == ssize*scnt*sides*ntrk) return 100; return 0; } -bool pc98fdi_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool pc98fdi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint8_t h[32]; + size_t actual; - io_generic_read(io, h, 0, 32); + uint8_t h[32]; + io.read_at(0, h, 32, actual); - uint32_t hsize = little_endianize_int32(*(uint32_t *)(h+0x8)); - uint32_t sector_size = little_endianize_int32(*(uint32_t *)(h+0x10)); - uint32_t sector_count = little_endianize_int32(*(uint32_t *)(h+0x14)); - uint32_t head_count = little_endianize_int32(*(uint32_t *)(h+0x18)); - uint32_t track_count = little_endianize_int32(*(uint32_t *)(h+0x1c)); + uint32_t const hsize = little_endianize_int32(*(uint32_t *)(h+0x8)); + uint32_t const sector_size = little_endianize_int32(*(uint32_t *)(h+0x10)); + uint32_t const sector_count = little_endianize_int32(*(uint32_t *)(h+0x14)); + uint32_t const head_count = little_endianize_int32(*(uint32_t *)(h+0x18)); + uint32_t const track_count = little_endianize_int32(*(uint32_t *)(h+0x1c)); - int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; + int const cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; - int ssize; - for(ssize=0; (128 << ssize) < sector_size; ssize++) {}; + int ssize = 0; + while ((128 << ssize) < sector_size) + ssize++; desc_pc_sector sects[256]; uint8_t sect_data[65536]; for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { - io_generic_read(io, sect_data, hsize + sector_size*sector_count*(track*head_count + head), sector_size*sector_count); + io.read_at(hsize + sector_size*sector_count*(track*head_count + head), sect_data, sector_size*sector_count, actual); for(int i=0; i<sector_count; i++) { sects[i].track = track; diff --git a/src/lib/formats/pc98fdi_dsk.h b/src/lib/formats/pc98fdi_dsk.h index 1c60f059cbe..1c539f06094 100644 --- a/src/lib/formats/pc98fdi_dsk.h +++ b/src/lib/formats/pc98fdi_dsk.h @@ -20,8 +20,8 @@ class pc98fdi_format : public floppy_image_format_t public: pc98fdi_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/pc_dsk.cpp b/src/lib/formats/pc_dsk.cpp index c814afbe6dc..6fe2a82196a 100644 --- a/src/lib/formats/pc_dsk.cpp +++ b/src/lib/formats/pc_dsk.cpp @@ -8,10 +8,12 @@ *********************************************************************/ +#include "formats/pc_dsk.h" + +#include "ioprocs.h" + #include <cstring> -#include <cassert> -#include "formats/pc_dsk.h" pc_format::pc_format() : upd765_format(formats) { @@ -32,9 +34,12 @@ const char *pc_format::extensions() const return "dsk,ima,img,ufi,360"; } -int pc_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int pc_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) { + return 0; + } /* some 360K images have a 512-byte header */ if (size == 368640 + 0x200) { diff --git a/src/lib/formats/pc_dsk.h b/src/lib/formats/pc_dsk.h index d53879611b9..8c99a35457f 100644 --- a/src/lib/formats/pc_dsk.h +++ b/src/lib/formats/pc_dsk.h @@ -20,7 +20,7 @@ class pc_format : public upd765_format public: pc_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/poly_dsk.cpp b/src/lib/formats/poly_dsk.cpp index a865729864e..8845643eb72 100644 --- a/src/lib/formats/poly_dsk.cpp +++ b/src/lib/formats/poly_dsk.cpp @@ -10,6 +10,9 @@ #include "poly_dsk.h" +#include "ioprocs.h" + + poly_cpm_format::poly_cpm_format() { } @@ -34,30 +37,35 @@ bool poly_cpm_format::supports_save() const return true; } -int poly_cpm_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int poly_cpm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint8_t boot[16]; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; // check for valid sizes if (size == 630784 || size == 622592 || size == 256256) { // check for Poly CP/M boot sector - io_generic_read(io, boot, 0, 16); + uint8_t boot[16]; + size_t actual; + io.read_at(0, boot, 16, actual); if (memcmp(boot, "\x86\xc3\xb7\x00\x00\x8e\x10\xc0\xbf\x00\x01\xbf\xe0\x60\x00\x00", 16) == 0) { return 100; } } + return 0; } -bool poly_cpm_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool poly_cpm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int total_tracks, spt, bps, head_num; - - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size) || io.seek(0, SEEK_SET)) + return false; + int total_tracks, spt, bps, head_num; switch (size) { case 622592: @@ -83,8 +91,7 @@ bool poly_cpm_format::load(io_generic *io, uint32_t form_factor, const std::vect break; } - int cell_count = (form_factor == floppy_image::FF_525) ? 50000 : 100000; - int offset = 0; + int const cell_count = (form_factor == floppy_image::FF_525) ? 50000 : 100000; for (int track = 0; track < total_tracks; track++) for (int head = 0; head < head_num; head++) @@ -105,8 +112,8 @@ bool poly_cpm_format::load(io_generic *io, uint32_t form_factor, const std::vect sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = §_data[sdatapos]; - io_generic_read(io, sects[i].data, offset, bps); - offset += bps; + size_t actual; + io.read(sects[i].data, bps, actual); sdatapos += bps; } // gap sizes unverified diff --git a/src/lib/formats/poly_dsk.h b/src/lib/formats/poly_dsk.h index 8fd3c9be4a5..8afb6836302 100644 --- a/src/lib/formats/poly_dsk.h +++ b/src/lib/formats/poly_dsk.h @@ -20,8 +20,8 @@ public: virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; }; diff --git a/src/lib/formats/rx50_dsk.cpp b/src/lib/formats/rx50_dsk.cpp index d0d8f270c56..f81e2fa5b67 100644 --- a/src/lib/formats/rx50_dsk.cpp +++ b/src/lib/formats/rx50_dsk.cpp @@ -29,11 +29,11 @@ FORMAT A: /F:160 on DOS; turn MEDIACHK ON ************************************************************************/ -#include <cassert> - -#include "flopimg.h" #include "formats/rx50_dsk.h" +#include "ioprocs.h" + + // Controller: WD1793 // TRACK LAYOUT IS UNVERIFED. SEE SOURCES: // - 'esq_dsk16' (uses WD 1772) @@ -95,12 +95,17 @@ bool rx50img_format::supports_save() const return true; } -void rx50img_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void rx50img_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { head_count = 1; uint32_t expected_size = 0; - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + { + track_count = head_count = sector_count = 0; + return; + } track_count = 80; sector_count = 10; @@ -124,7 +129,7 @@ void rx50img_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &he track_count = head_count = sector_count = 0; } -int rx50img_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int rx50img_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -135,7 +140,7 @@ int rx50img_format::identify(io_generic *io, uint32_t form_factor, const std::ve } // /* Sectors are numbered 1 to 10 */ -bool rx50img_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool rx50img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -153,7 +158,8 @@ bool rx50img_format::load(io_generic *io, uint32_t form_factor, const std::vecto int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { - io_generic_read(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual); generate_track(rx50_10_desc, track, head, sectors, sector_count, 102064, image); // 98480 } } @@ -163,7 +169,7 @@ bool rx50img_format::load(io_generic *io, uint32_t form_factor, const std::vecto return true; } -bool rx50img_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool rx50img_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); @@ -199,7 +205,8 @@ bool rx50img_format::save(io_generic *io, const std::vector<uint32_t> &variants, for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); } } return true; diff --git a/src/lib/formats/rx50_dsk.h b/src/lib/formats/rx50_dsk.h index 9cac83bd67f..d28ea398d30 100644 --- a/src/lib/formats/rx50_dsk.h +++ b/src/lib/formats/rx50_dsk.h @@ -23,9 +23,9 @@ class rx50img_format : public floppy_image_format_t public: rx50img_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -35,7 +35,7 @@ public: static const desc_e rx50_10_desc[]; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; extern const floppy_format_type FLOPPY_RX50IMG_FORMAT; diff --git a/src/lib/formats/sdd_dsk.cpp b/src/lib/formats/sdd_dsk.cpp index cac33948db0..f3e8df51bda 100644 --- a/src/lib/formats/sdd_dsk.cpp +++ b/src/lib/formats/sdd_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/sdd_dsk.h" +#include "ioprocs.h" + + sdd_format::sdd_format() : wd177x_format(formats) { } diff --git a/src/lib/formats/sdf_dsk.cpp b/src/lib/formats/sdf_dsk.cpp index 223b6dc8d8a..f57540f3c35 100644 --- a/src/lib/formats/sdf_dsk.cpp +++ b/src/lib/formats/sdf_dsk.cpp @@ -12,7 +12,9 @@ *********************************************************************/ #include "sdf_dsk.h" -#include <cassert> + +#include "ioprocs.h" + sdf_format::sdf_format() { @@ -37,18 +39,18 @@ const char *sdf_format::extensions() const } -int sdf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int sdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t header[HEADER_SIZE]; - uint64_t size = io_generic_size(io); - - if (size < HEADER_SIZE) + uint64_t size; + if (io.length(size) || (size < HEADER_SIZE)) { return 0; } - io_generic_read(io, header, 0, HEADER_SIZE); + size_t actual; + io.read_at(0, header, HEADER_SIZE, actual); int tracks = header[4]; int heads = header[5]; @@ -74,13 +76,14 @@ int sdf_format::identify(io_generic *io, uint32_t form_factor, const std::vector } -bool sdf_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool sdf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; uint8_t header[HEADER_SIZE]; std::vector<uint8_t> track_data(TOTAL_TRACK_SIZE); std::vector<uint32_t> raw_track_data; - io_generic_read(io, header, 0, HEADER_SIZE); + io.read_at(0, header, HEADER_SIZE, actual); const int tracks = header[4]; const int heads = header[5]; @@ -104,7 +107,7 @@ bool sdf_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui raw_track_data.clear(); // Read track - io_generic_read(io, &track_data[0], HEADER_SIZE + ( heads * track + head ) * TOTAL_TRACK_SIZE, TOTAL_TRACK_SIZE); + io.read_at(HEADER_SIZE + (heads * track + head) * TOTAL_TRACK_SIZE, &track_data[0], TOTAL_TRACK_SIZE, actual); int sector_count = track_data[0]; @@ -181,7 +184,7 @@ bool sdf_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool sdf_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool sdf_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/sdf_dsk.h b/src/lib/formats/sdf_dsk.h index fe3f6eb7a98..b86692f618a 100644 --- a/src/lib/formats/sdf_dsk.h +++ b/src/lib/formats/sdf_dsk.h @@ -22,9 +22,9 @@ class sdf_format : public floppy_image_format_t public: sdf_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/st_dsk.cpp b/src/lib/formats/st_dsk.cpp index cb363cbe3e3..d044bc5bdac 100644 --- a/src/lib/formats/st_dsk.cpp +++ b/src/lib/formats/st_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/st_dsk.h" +#include "ioprocs.h" + + st_format::st_format() { } @@ -36,18 +37,20 @@ bool st_format::supports_save() const return true; } -void st_format::find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) +void st_format::find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count) { - uint64_t size = io_generic_size(io); - for(track_count=80; track_count <= 82; track_count++) - for(head_count=1; head_count <= 2; head_count++) - for(sector_count=9; sector_count <= 11; sector_count++) - if(size == (uint32_t)512*track_count*head_count*sector_count) - return; + uint64_t size; + if(!io.length(size)) { + for(track_count=80; track_count <= 82; track_count++) + for(head_count=1; head_count <= 2; head_count++) + for(sector_count=9; sector_count <= 11; sector_count++) + if(size == (uint32_t)512*track_count*head_count*sector_count) + return; + } track_count = head_count = sector_count = 0; } -int st_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int st_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -57,7 +60,7 @@ int st_format::identify(io_generic *io, uint32_t form_factor, const std::vector< return 0; } -bool st_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool st_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t track_count, head_count, sector_count; find_size(io, track_count, head_count, sector_count); @@ -73,7 +76,8 @@ bool st_format::load(io_generic *io, uint32_t form_factor, const std::vector<uin int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { - io_generic_read(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual); generate_track(atari_st_fcp_get_desc(track, head, head_count, sector_count), track, head, sectors, sector_count, 100000, image); } @@ -84,7 +88,7 @@ bool st_format::load(io_generic *io, uint32_t form_factor, const std::vector<uin return true; } -bool st_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool st_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); @@ -109,7 +113,8 @@ bool st_format::save(io_generic *io, const std::vector<uint32_t> &variants, flop for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); - io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); + size_t actual; + io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); } } @@ -141,10 +146,11 @@ bool msa_format::supports_save() const return true; } -void msa_format::read_header(io_generic *io, uint16_t &sign, uint16_t §, uint16_t &head, uint16_t &strack, uint16_t &etrack) +void msa_format::read_header(util::random_read &io, uint16_t &sign, uint16_t §, uint16_t &head, uint16_t &strack, uint16_t &etrack) { uint8_t h[10]; - io_generic_read(io, h, 0, 10); + size_t actual; + io.read_at(0, h, 10, actual); sign = (h[0] << 8) | h[1]; sect = (h[2] << 8) | h[3]; head = (h[4] << 8) | h[5]; @@ -206,7 +212,7 @@ bool msa_format::compress(const uint8_t *buffer, int usize, uint8_t *dest, int & return dst < usize; } -int msa_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int msa_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { uint16_t sign, sect, head, strack, etrack; read_header(io, sign, sect, head, strack, etrack); @@ -220,7 +226,7 @@ int msa_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool msa_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool msa_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { uint16_t sign, sect, heads, strack, etrack; read_header(io, sign, sect, heads, strack, etrack); @@ -238,11 +244,12 @@ bool msa_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui for(int track=strack; track <= etrack; track++) { for(int head=0; head <= heads; head++) { + size_t actual; uint8_t th[2]; - io_generic_read(io, th, pos, 2); + io.read_at(pos, th, 2, actual); pos += 2; int tsize = (th[0] << 8) | th[1]; - io_generic_read(io, sectdata, pos, tsize); + io.read_at(pos, sectdata, tsize, actual); pos += tsize; if(tsize < track_size) { if(!uncompress(sectdata, tsize, track_size)) @@ -258,7 +265,7 @@ bool msa_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool msa_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool msa_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); @@ -289,9 +296,10 @@ bool msa_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo header[8] = 0; header[9] = track_count-1; - io_generic_write(io, header, 0, 10); - - int pos = 10; + if(io.seek(0, SEEK_SET)) + return false; + size_t actual; + io.write(header, 10, actual); uint8_t sectdata[11*512]; uint8_t compdata[11*512]; @@ -305,16 +313,14 @@ bool msa_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo uint8_t th[2]; th[0] = csize >> 8; th[1] = csize; - io_generic_write(io, th, pos, 2); - io_generic_write(io, compdata, pos+2, csize); - pos += 2+csize; + io.write(th, 2, actual); + io.write(compdata, csize, actual); } else { uint8_t th[2]; th[0] = track_size >> 8; th[1] = track_size; - io_generic_write(io, th, pos, 2); - io_generic_write(io, sectdata, pos+2, track_size); - pos += 2+track_size; + io.write(th, 2, actual); + io.write(sectdata, track_size, actual); } } } diff --git a/src/lib/formats/st_dsk.h b/src/lib/formats/st_dsk.h index ce501a9f516..34f303bb1ae 100644 --- a/src/lib/formats/st_dsk.h +++ b/src/lib/formats/st_dsk.h @@ -19,9 +19,9 @@ class st_format : public floppy_image_format_t public: st_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -29,7 +29,7 @@ public: virtual bool supports_save() const override; private: - void find_size(io_generic *io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); }; class msa_format : public floppy_image_format_t @@ -37,9 +37,9 @@ class msa_format : public floppy_image_format_t public: msa_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -49,7 +49,7 @@ public: private: bool uncompress(uint8_t *buffer, int csize, int usize); bool compress(const uint8_t *src, int usize, uint8_t *dest, int &csize); - void read_header(io_generic *io, uint16_t &sign, uint16_t §, uint16_t &head, uint16_t &strack, uint16_t &etrack); + void read_header(util::random_read &io, uint16_t &sign, uint16_t §, uint16_t &head, uint16_t &strack, uint16_t &etrack); }; extern const floppy_format_type FLOPPY_ST_FORMAT; diff --git a/src/lib/formats/svi_dsk.cpp b/src/lib/formats/svi_dsk.cpp index e3cfa294fcb..0a05bd15c80 100644 --- a/src/lib/formats/svi_dsk.cpp +++ b/src/lib/formats/svi_dsk.cpp @@ -10,6 +10,9 @@ #include "svi_dsk.h" +#include "ioprocs.h" + + svi_format::svi_format() { } @@ -29,9 +32,11 @@ const char *svi_format::extensions() const return "dsk"; } -int svi_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int svi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if (io.length(size)) + return 0; if (size == 172032 || size == 346112) return 50; @@ -39,11 +44,13 @@ int svi_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool svi_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool svi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t size = io_generic_size(io); - int head_count; + uint64_t size; + if (io.length(size)) + return false; + int head_count; switch (size) { case 172032: head_count = 1; break; @@ -51,7 +58,8 @@ bool svi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui default: return false; } - int file_offset = 0; + if (io.seek(0, SEEK_SET)) + return false; for (int track = 0; track < 40; track++) { @@ -75,10 +83,10 @@ bool svi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui sectors[i].bad_crc = false; sectors[i].data = §or_data[sector_offset]; - io_generic_read(io, sectors[i].data, file_offset, sector_size); + size_t actual; + io.read(sectors[i].data, sector_size, actual); sector_offset += sector_size; - file_offset += sector_size; } if (track == 0 && head == 0) @@ -91,9 +99,10 @@ bool svi_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool svi_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool svi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t file_offset = 0; + if (io.seek(0, SEEK_SET)) + return false; int track_count, head_count; image->get_actual_geometry(track_count, head_count); @@ -104,8 +113,8 @@ bool svi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo for (int i = 0; i < 18; i++) { - io_generic_write(io, sectors[i + 1].data(), file_offset, 128); - file_offset += 128; + size_t actual; + io.write(sectors[i + 1].data(), 128, actual); } // rest are mfm tracks @@ -121,8 +130,8 @@ bool svi_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo for (int i = 0; i < 17; i++) { - io_generic_write(io, sectors[i + 1].data(), file_offset, 256); - file_offset += 256; + size_t actual; + io.write(sectors[i + 1].data(), 256, actual); } } } diff --git a/src/lib/formats/svi_dsk.h b/src/lib/formats/svi_dsk.h index 57f4f89ccca..a631bdf498c 100644 --- a/src/lib/formats/svi_dsk.h +++ b/src/lib/formats/svi_dsk.h @@ -23,9 +23,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; }; diff --git a/src/lib/formats/td0_dsk.cpp b/src/lib/formats/td0_dsk.cpp index edac0aae010..345a242c86b 100644 --- a/src/lib/formats/td0_dsk.cpp +++ b/src/lib/formats/td0_dsk.cpp @@ -16,9 +16,11 @@ #include "flopimg.h" -#include <cassert> +#include "ioprocs.h" + #include <cstring> + #define BUFSZ 512 // new input buffer /* LZSS Parameters */ @@ -59,7 +61,16 @@ struct tdlzhuf { struct td0dsk_t { - io_generic *floppy_file; +public: + td0dsk_t(util::random_read &f) : floppy_file(f) { } + + void set_floppy_file_offset(uint64_t o) { floppy_file_offset = o; } + + void init_Decode(); + int Decode(uint8_t *buf, int len); + +private: + util::random_read &floppy_file; uint64_t floppy_file_offset; struct tdlzhuf tdctl; @@ -87,29 +98,10 @@ struct td0dsk_t void update(int c); int16_t DecodeChar(); int16_t DecodePosition(); - void init_Decode(); - int Decode(uint8_t *buf, int len); }; //static td0dsk_t td0dsk; -struct floppy_image_legacy -{ - struct io_generic io; - - const struct FloppyFormat *floppy_option; - struct FloppyCallbacks format; - - /* loaded track stuff */ - int loaded_track_head; - int loaded_track_index; - uint32_t loaded_track_size; - void *loaded_track_data; - uint8_t loaded_track_status; - uint8_t flags; -}; - - static struct td0dsk_tag *get_tag(floppy_image_legacy *floppy) { struct td0dsk_tag *tag; @@ -332,11 +324,13 @@ static floperr_t td0_get_indexed_sector_info(floppy_image_legacy *floppy, int he int td0dsk_t::data_read(uint8_t *buf, uint16_t size) { - uint64_t image_size = io_generic_size(floppy_file); + uint64_t image_size = 0; + floppy_file.length(image_size); if (size > image_size - floppy_file_offset) { size = image_size - floppy_file_offset; } - io_generic_read(floppy_file,buf,floppy_file_offset,size); + size_t actual; + floppy_file.read_at(floppy_file_offset, buf, size, actual); floppy_file_offset += size; return size; } @@ -675,7 +669,6 @@ int td0dsk_t::Decode(uint8_t *buf, int len) /* Decoding/Uncompressing */ FLOPPY_CONSTRUCT( td0_dsk_construct ) { - td0dsk_t state; struct FloppyCallbacks *callbacks; struct td0dsk_tag *tag; uint8_t *header; @@ -706,9 +699,9 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) int rd; int off = 12; int size = 0; - state.floppy_file = &(floppy->io); + td0dsk_t state(floppy_get_io(floppy)); state.init_Decode(); - state.floppy_file_offset = 12; + state.set_floppy_file_offset(12); do { if((rd = state.Decode(obuf, BUFSZ)) > 0) size += rd; @@ -720,7 +713,7 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) return FLOPPY_ERROR_OUTOFMEMORY; } memcpy(tag->data,obuf,12); - state.floppy_file_offset = 12; + state.set_floppy_file_offset(12); state.init_Decode(); do { @@ -815,20 +808,22 @@ const char *td0_format::extensions() const return "td0"; } -int td0_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int td0_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t h[7]; - io_generic_read(io, h, 0, 7); + io.read_at(0, h, 7, actual); if(((h[0] == 'T') && (h[1] == 'D')) || ((h[0] == 't') && (h[1] == 'd'))) { - return 100; + return 100; } return 0; } -bool td0_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool td0_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; int track_count = 0; int head_count = 0; int track_spt; @@ -837,20 +832,24 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui std::vector<uint8_t> imagebuf(max_size); uint8_t header[12]; - io_generic_read(io, header, 0, 12); + io.read_at(0, header, 12, actual); head_count = header[9]; if(header[0] == 't') { - td0dsk_t disk_decode; + td0dsk_t disk_decode(io); - disk_decode.floppy_file = io; disk_decode.init_Decode(); - disk_decode.floppy_file_offset = 12; + disk_decode.set_floppy_file_offset(12); disk_decode.Decode(&imagebuf[0], max_size); } else - io_generic_read(io, &imagebuf[0], 12, io_generic_size(io)); + { + uint64_t image_size; + if(io.length(image_size)) + return false; + io.read_at(12, &imagebuf[0], image_size, actual); + } if(header[7] & 0x80) offset = 10 + imagebuf[2] + (imagebuf[3] << 8); @@ -1024,7 +1023,7 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui } -bool td0_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool td0_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { return false; } diff --git a/src/lib/formats/td0_dsk.h b/src/lib/formats/td0_dsk.h index b4656305920..cf625374130 100644 --- a/src/lib/formats/td0_dsk.h +++ b/src/lib/formats/td0_dsk.h @@ -13,9 +13,9 @@ class td0_format : public floppy_image_format_t public: td0_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/ti99_dsk.cpp b/src/lib/formats/ti99_dsk.cpp index 06ce98dfda0..507d7dc0ae0 100644 --- a/src/lib/formats/ti99_dsk.cpp +++ b/src/lib/formats/ti99_dsk.cpp @@ -43,6 +43,8 @@ #include "ti99_dsk.h" #include "imageutl.h" +#include "ioprocs.h" + #include "osdcore.h" // osd_printf_* (in osdcore.h) #include <cstring> @@ -80,13 +82,16 @@ int ti99_floppy_format::get_encoding(int cell_size) /* Load the image from disk and convert it into a sequence of flux levels. */ -bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool ti99_floppy_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + uint64_t file_size; + if (io.length(file_size)) + return false; + int cell_size = 0; int sector_count = 0; int heads = 0; int log_track_count = 0; - int file_size = io_generic_size(io); bool img_high_tpi = false; bool drive_high_tpi = false; @@ -211,7 +216,7 @@ bool ti99_floppy_format::load(io_generic *io, uint32_t form_factor, const std::v /* Save all tracks to the image file. */ -bool ti99_floppy_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool ti99_floppy_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { uint8_t sectordata[9216]; // max size (36*256) @@ -916,9 +921,12 @@ const char *ti99_sdf_format::extensions() const return "dsk"; } -int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ti99_sdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t file_size = io_generic_size(io); + uint64_t file_size; + if (io.length(file_size)) + return 0; + int vote = 0; // Adding support for another sector image format which adds 768 bytes @@ -947,7 +955,8 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor, const std::v { // Read first sector (Volume Information Block) ti99vib vib; - io_generic_read(io, &vib, 0, sizeof(ti99vib)); + size_t actual; + io.read_at(0, &vib, sizeof(ti99vib), actual); // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) @@ -964,10 +973,14 @@ int ti99_sdf_format::identify(io_generic *io, uint32_t form_factor, const std::v return vote; } -void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) +void ti99_sdf_format::determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) { - uint64_t file_size = io_generic_size(io); - ti99vib vib; + uint64_t file_size; + if (io.length(file_size)) + { + cell_size = sector_count = heads = tracks = 0; + return; + } cell_size = 0; sector_count = 0; @@ -980,7 +993,9 @@ void ti99_sdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto file_size -= 768; // Read first sector - io_generic_read(io, &vib, 0, sizeof(ti99vib)); + ti99vib vib; + size_t actual; + io.read_at(0, &vib, sizeof(ti99vib), actual); // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) @@ -1059,13 +1074,14 @@ int ti99_sdf_format::get_track_size(int sector_count) return sector_count * SECTOR_SIZE; } -void ti99_sdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) +void ti99_sdf_format::load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) { // Calculate the track offset from the beginning of the image file int logicaltrack = (head==0)? track : (2*trackcount - track - 1); int position = logicaltrack * get_track_size(sectorcount); - io_generic_read(io, sectordata, position, sectorcount*SECTOR_SIZE); + size_t actual; + io.read_at(position, sectordata, sectorcount*SECTOR_SIZE, actual); // Interleave and skew int interleave = 7; @@ -1133,19 +1149,18 @@ std::string ti99_floppy_format::dumpline(uint8_t* line, int address) const Write the data to the disk. We have a list of sector positions, so we just need to go through that list and save each sector in the sector data. */ -void ti99_sdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) +void ti99_sdf_format::write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) { - uint8_t* buf; - int logicaltrack = head * track_count; logicaltrack += ((head&1)==0)? track : (track_count - 1 - track); int trackoffset = logicaltrack * sector_count * SECTOR_SIZE; for (int i=0; i < sector_count; i++) { - buf = sectordata + i * SECTOR_SIZE; + uint8_t const *const buf = sectordata + i * SECTOR_SIZE; LOGMASKED(LOG_DETAIL, "[ti99_dsk] Writing sector %d (offset %06x)\n", sector[i], sector[i] * SECTOR_SIZE); - io_generic_write(io, buf, trackoffset + sector[i] * SECTOR_SIZE, SECTOR_SIZE); + size_t actual; + io.write_at(trackoffset + sector[i] * SECTOR_SIZE, buf, SECTOR_SIZE, actual); } } @@ -1209,7 +1224,7 @@ const char *ti99_tdf_format::extensions() const /* Determine whether the image file can be interpreted as a track dump */ -int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int ti99_tdf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int vote = 0; uint8_t fulltrack[6872]; @@ -1232,7 +1247,8 @@ int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor, const std::v LOGMASKED(LOG_INFO, "[ti99_dsk] Image file length matches TDF\n"); // Fetch track 0 - io_generic_read(io, fulltrack, 0, get_track_size(sector_count)); + size_t actual; + io.read_at(0, fulltrack, get_track_size(sector_count), actual); if (sector_count == 9) { @@ -1279,9 +1295,14 @@ int ti99_tdf_format::identify(io_generic *io, uint32_t form_factor, const std::v Find the proper format for a given image file. Tracks are counted per side. Note that only two formats are actually compatible with the PC99 emulator. */ -void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) +void ti99_tdf_format::determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) { - uint64_t file_size = io_generic_size(io); + uint64_t file_size; + if (io.length(file_size)) + { + cell_size = sector_count = heads = tracks = 0; + return; + } // LOGMASKED(LOG_INFO, "[ti99_dsk] Image size = %ld\n", file_size); // doesn't compile switch (file_size) @@ -1336,13 +1357,14 @@ void ti99_tdf_format::determine_sizes(io_generic *io, int& cell_size, int& secto track from scratch. TDF is not as flexible as it suggests, it does not allow different gap lengths and so on. */ -void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) +void ti99_tdf_format::load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) { + size_t actual; uint8_t fulltrack[12544]; // space for a full TDF track // Read beginning of track 0. We need this to get the first gap, according // to the format - io_generic_read(io, fulltrack, 0, 100); + io.read_at(0, fulltrack, 100, actual); int offset = 0; int tracksize = get_track_size(sectorcount); @@ -1383,7 +1405,7 @@ void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *secto int base = (head * trackcount + track) * tracksize; int position = 0; - io_generic_read(io, fulltrack, base, tracksize); + io.read_at(base, fulltrack, tracksize, actual); for (int i=0; i < sectorcount; i++) { @@ -1431,7 +1453,7 @@ void ti99_tdf_format::load_track(io_generic *io, uint8_t *sectordata, int *secto need the sector contents and the sector sequence, which are passed via sectordata, sector, and sector_count. */ -void ti99_tdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) +void ti99_tdf_format::write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) { uint8_t trackdata[12544]; int offset = ((track_count * head) + track) * get_track_size(sector_count); @@ -1485,7 +1507,8 @@ void ti99_tdf_format::write_track(io_generic *io, uint8_t *sectordata, int *sect for (int i=0; i < param[WGAP3]; i++) trackdata[pos++] = param[WGAPBYTE]; } for (int i=0; i < param[WGAP4]; i++) trackdata[pos++] = param[WGAPBYTE]; - io_generic_write(io, trackdata, offset, get_track_size(sector_count)); + size_t actual; + io.write_at(offset, trackdata, get_track_size(sector_count), actual); } int ti99_tdf_format::get_track_size(int sector_count) diff --git a/src/lib/formats/ti99_dsk.h b/src/lib/formats/ti99_dsk.h index 5b59b164344..6590d1e7dd2 100644 --- a/src/lib/formats/ti99_dsk.h +++ b/src/lib/formats/ti99_dsk.h @@ -23,8 +23,8 @@ class ti99_floppy_format : public floppy_image_format_t { public: bool supports_save() const override { return true; } - bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; protected: uint8_t get_data_from_encoding(uint16_t raw); @@ -32,10 +32,10 @@ protected: virtual int min_heads() =0; - virtual void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) =0; + virtual void determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) =0; virtual int get_track_size(int sector_count) =0; - virtual void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) =0; - virtual void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) =0; + virtual void load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) =0; + virtual void write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) =0; int get_encoding(int cell_size); @@ -53,16 +53,16 @@ protected: class ti99_sdf_format : public ti99_floppy_format { public: - int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; const char *name() const override; const char *description() const override; const char *extensions() const override; private: - void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) override; + void determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) override; int get_track_size(int sector_count) override; - void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override; - void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sector_count, int track_count) override; + void write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override; + void load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sector_count, int track_count) override; // This format supports single-sided images int min_heads() override { return 1; } @@ -92,15 +92,15 @@ extern const floppy_format_type FLOPPY_TI99_SDF_FORMAT; class ti99_tdf_format : public ti99_floppy_format { public: - int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; const char *name() const override; const char *description() const override; const char *extensions() const override; private: - void determine_sizes(io_generic *io, int& cell_size, int& sector_count, int& heads, int& tracks) override; - void load_track(io_generic *io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) override; - void write_track(io_generic *io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override; + void determine_sizes(util::random_read &io, int& cell_size, int& sector_count, int& heads, int& tracks) override; + void load_track(util::random_read &io, uint8_t *sectordata, int *sector, int *secoffset, int head, int track, int sectorcount, int trackcount) override; + void write_track(util::random_read_write &io, uint8_t *sectordata, int *sector, int track, int head, int sector_count, int track_count) override; int get_track_size(int sector_count) override; // This format only supports double-sided images diff --git a/src/lib/formats/trd_dsk.cpp b/src/lib/formats/trd_dsk.cpp index 26b6ce5b6a5..4236259cca5 100644 --- a/src/lib/formats/trd_dsk.cpp +++ b/src/lib/formats/trd_dsk.cpp @@ -8,10 +8,11 @@ *********************************************************************/ -#include <cassert> - #include "formats/trd_dsk.h" +#include "ioprocs.h" + + trd_format::trd_format() : wd177x_format(formats) { } @@ -31,10 +32,13 @@ const char *trd_format::extensions() const return "trd"; } -int trd_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int trd_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + uint64_t size; + if (io.length(size)) + return -1; + int index = -1; - uint64_t size = io_generic_size(io); for (int i = 0; formats[i].form_factor; i++) { const format &f = formats[i]; @@ -47,12 +51,13 @@ int trd_format::find_size(io_generic *io, uint32_t form_factor, const std::vecto { index = i; // at least size match, save it for the case if there will be no exact matches + size_t actual; uint8_t sectdata[0x100]; if (f.encoding == floppy_image::MFM) - io_generic_read(io, sectdata, 0x800, 0x100); + io.read_at(0x800, sectdata, 0x100, actual); else { - io_generic_read(io, sectdata, 0x100, 0x100); + io.read_at(0x100, sectdata, 0x100, actual); for (int i = 0; i < 0x100; i++) sectdata[i] ^= 0xff; } diff --git a/src/lib/formats/trd_dsk.h b/src/lib/formats/trd_dsk.h index 6f19f9976a5..c5a411c60bb 100644 --- a/src/lib/formats/trd_dsk.h +++ b/src/lib/formats/trd_dsk.h @@ -24,7 +24,7 @@ public: private: static const format formats[]; - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; }; extern const floppy_format_type FLOPPY_TRD_FORMAT; diff --git a/src/lib/formats/trs80_dsk.cpp b/src/lib/formats/trs80_dsk.cpp index f010a24e570..acd48368239 100644 --- a/src/lib/formats/trs80_dsk.cpp +++ b/src/lib/formats/trs80_dsk.cpp @@ -66,6 +66,9 @@ Description of JV3: #include "trs80_dsk.h" +#include "ioprocs.h" + + jv1_format::jv1_format() : wd177x_format(formats) { } @@ -132,15 +135,18 @@ const char *jv3_format::extensions() const return "jv3,dsk"; } -int jv3_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int jv3_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint32_t image_size = io_generic_size(io); + uint64_t image_size; + if (io.length(image_size)) + return 0; if (image_size < 0x2200) return 0; // too small, silent return std::vector<uint8_t> data(image_size); - io_generic_read(io, data.data(), 0, image_size); + size_t actual; + io.read_at(0, data.data(), image_size, actual); const uint32_t entries = 2901; const uint32_t header_size = entries *3 +1; @@ -181,20 +187,20 @@ int jv3_format::identify(io_generic *io, uint32_t form_factor, const std::vector // validate so we don't overrun the array if (track >= MAX_TRACKS) { - printf("jv3_format::identify - track %d exceeds maximum allowed (%d)\n",track,MAX_TRACKS-1); + osd_printf_info("jv3_format::identify - track %d exceeds maximum allowed (%d)\n",track,MAX_TRACKS-1); return 0; } if (sector >= MAX_SECTORS) { - printf("jv3_format::identify - sector %d exceeds maximum allowed (%d)\n",sector,MAX_SECTORS-1); + osd_printf_info("jv3_format::identify - sector %d exceeds maximum allowed (%d)\n",sector,MAX_SECTORS-1); return 0; } // check if sector already exists if (sector_array[flag_side][track][sector]) { - printf("jv3_format::identify - side %d track %d sector %d is duplicated\n",flag_side,track,sector); + osd_printf_info("jv3_format::identify - side %d track %d sector %d is duplicated\n",flag_side,track,sector); return 0; } @@ -214,21 +220,25 @@ int jv3_format::identify(io_generic *io, uint32_t form_factor, const std::vector // Is all data in the image? (unused tracks at the end are optional) if (last_data > image_size) { - printf("jv3_format::identify - disk is missing some data. Expected 0x%X, Actual = 0x%X\n",last_data,image_size); + osd_printf_info("jv3_format::identify - disk is missing some data. Expected 0x%X, Actual = 0x%X\n",last_data,image_size); return 0; } return 80; } -bool jv3_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool jv3_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { // disk has already been validated in every way except if it exceeds drive tracks, we do that below - printf("Disk detected as JV3\n");fflush(stdout); + osd_printf_info("Disk detected as JV3\n"); int drive_tracks, drive_sides; image->get_maximal_geometry(drive_tracks, drive_sides); - std::vector<uint8_t> data(io_generic_size(io)); - io_generic_read(io, data.data(), 0, data.size()); + uint64_t image_size; + if (io.length(image_size)) + return false; + std::vector<uint8_t> data(image_size); + size_t actual; + io.read_at(0, data.data(), data.size(), actual); const uint32_t entries = 2901; const uint32_t header_size = entries *3 +1; bool is_dd = false, is_ds = false; @@ -313,7 +323,7 @@ bool jv3_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui data_ptr += sector_size; } - //printf("Side %d, Track %d, %s density\n",curr_side,curr_track,ddensity ? "Double" : "Single"); + //osd_printf_verbose("Side %d, Track %d, %s density\n",curr_side,curr_track,ddensity ? "Double" : "Single"); if (ddensity) { is_dd = true; @@ -344,7 +354,7 @@ bool jv3_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool jv3_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool jv3_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int track_count, head_count; image->get_actual_geometry(track_count, head_count); @@ -352,10 +362,15 @@ bool jv3_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo if (track_count) { // If the disk already exists, find out if it's writable - std::vector<uint8_t> data(io_generic_size(io)); - io_generic_read(io, data.data(), 0, data.size()); - if ((data.size() >= 0x2200) && (data[0x21ff] == 0)) - return false; // disk is readonly + uint64_t image_size; + if (!io.length(image_size)) + { + std::vector<uint8_t> data(image_size); + size_t actual; + io.read_at(0, data.data(), data.size(), actual); + if ((data.size() >= 0x2200) && (data[0x21ff] == 0)) + return false; // disk is readonly + } } uint32_t data_ptr = 0x2200, sect_ptr = 0; @@ -396,7 +411,8 @@ bool jv3_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo header[sect_ptr++] = track; header[sect_ptr++] = i; header[sect_ptr++] = head ? 0x10 : 0; - io_generic_write(io, &dummy[0], data_ptr, 256); + size_t actual; + io.write_at(data_ptr, &dummy[0], 256, actual); data_ptr += 256; } } @@ -417,14 +433,16 @@ bool jv3_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo flags |= (sectors[i].size() >> 8) ^1; flags |= head ? 0x10 : 0; header[sect_ptr++] = flags; - io_generic_write(io, sectors[i].data(), data_ptr, sectors[i].size()); + size_t actual; + io.write_at(data_ptr, sectors[i].data(), sectors[i].size(), actual); data_ptr += sectors[i].size(); } } } } // Save the header - io_generic_write(io, header, 0, 0x2200); + size_t actual; + io.write_at(0, header, 0x2200, actual); return true; } diff --git a/src/lib/formats/trs80_dsk.h b/src/lib/formats/trs80_dsk.h index 60618a93693..31955fe4a5e 100644 --- a/src/lib/formats/trs80_dsk.h +++ b/src/lib/formats/trs80_dsk.h @@ -35,9 +35,9 @@ class jv3_format : public floppy_image_format_t public: jv3_format(); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual const char *name() const override; virtual const char *description() const override; diff --git a/src/lib/formats/uniflex_dsk.cpp b/src/lib/formats/uniflex_dsk.cpp index fa5d9b50acc..f85da09b75e 100644 --- a/src/lib/formats/uniflex_dsk.cpp +++ b/src/lib/formats/uniflex_dsk.cpp @@ -10,7 +10,10 @@ */ #include "uniflex_dsk.h" -#include "formats/imageutl.h" +#include "imageutl.h" + +#include "ioprocs.h" + uniflex_format::uniflex_format() : wd177x_format(formats) { @@ -31,22 +34,26 @@ const char *uniflex_format::extensions() const return "dsk"; } -int uniflex_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int uniflex_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if (type != -1) return 75; + return 0; } -int uniflex_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int uniflex_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); - uint8_t sir[192]; + uint64_t size; + if (io.length(size)) + return -1; // Look at the SIR sector, the second sector. - io_generic_read(io, sir, 1 * 512, sizeof(sir)); + uint8_t sir[192]; + size_t actual; + io.read_at(1 * 512, sir, sizeof(sir), actual); uint16_t fdn_block_count = pick_integer_be(sir, 0x10, 2); uint32_t last_block_number = pick_integer_be(sir, 0x12, 3); diff --git a/src/lib/formats/uniflex_dsk.h b/src/lib/formats/uniflex_dsk.h index fad6741f533..af39a09678e 100644 --- a/src/lib/formats/uniflex_dsk.h +++ b/src/lib/formats/uniflex_dsk.h @@ -19,8 +19,8 @@ public: virtual const char *name() const override; virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; void build_sector_description(const format &f, uint8_t *sectdata, desc_s *sectors, int track, int head) const override; private: diff --git a/src/lib/formats/upd765_dsk.cpp b/src/lib/formats/upd765_dsk.cpp index e7118dde236..d0afab39352 100644 --- a/src/lib/formats/upd765_dsk.cpp +++ b/src/lib/formats/upd765_dsk.cpp @@ -10,14 +10,19 @@ #include "formats/upd765_dsk.h" +#include "ioprocs.h" + upd765_format::upd765_format(const format *_formats) : file_header_skip_bytes(0), file_footer_skip_bytes(0), formats(_formats) { } -int upd765_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +int upd765_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return -1; + for(int i=0; formats[i].form_factor; i++) { const format &f = formats[i]; if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) @@ -31,7 +36,7 @@ int upd765_format::find_size(io_generic *io, uint32_t form_factor, const std::ve return -1; } -int upd765_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int upd765_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor, variants); @@ -175,7 +180,7 @@ floppy_image_format_t::desc_e* upd765_format::get_desc_mfm(const format &f, int return desc; } -bool upd765_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool upd765_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { int type = find_size(io, form_factor, variants); if(type == -1) @@ -222,7 +227,8 @@ bool upd765_format::load(io_generic *io, uint32_t form_factor, const std::vector for(int track=0; track < f.track_count; track++) for(int head=0; head < f.head_count; head++) { build_sector_description(f, sectdata, sectors, track, head); - io_generic_read(io, sectdata, file_header_skip_bytes + (track*f.head_count + head)*track_size, track_size); + size_t actual; + io.read_at(file_header_skip_bytes + (track*f.head_count + head)*track_size, sectdata, track_size, actual); generate_track(desc, track, head, sectors, f.sector_count, total_size, image); } @@ -236,7 +242,7 @@ bool upd765_format::supports_save() const return true; } -bool upd765_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool upd765_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { // Count the number of formats int formats_count; @@ -346,7 +352,8 @@ bool upd765_format::save(io_generic *io, const std::vector<uint32_t> &variants, for(int head=0; head < f.head_count; head++) { build_sector_description(f, sectdata, sectors, track, head); extract_sectors(image, f, sectors, track, head); - io_generic_write(io, sectdata, (track*f.head_count + head)*track_size, track_size); + size_t actual; + io.write_at((track*f.head_count + head)*track_size, sectdata, track_size, actual); } return true; diff --git a/src/lib/formats/upd765_dsk.h b/src/lib/formats/upd765_dsk.h index e93a0f24326..48acfc02a88 100644 --- a/src/lib/formats/upd765_dsk.h +++ b/src/lib/formats/upd765_dsk.h @@ -39,9 +39,9 @@ public: // End the array with {} upd765_format(const format *formats); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; protected: @@ -50,7 +50,7 @@ protected: floppy_image_format_t::desc_e* get_desc_fm(const format &f, int ¤t_size, int &end_gap_index); floppy_image_format_t::desc_e* get_desc_mfm(const format &f, int ¤t_size, int &end_gap_index); - int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) const; + int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const; int compute_track_size(const format &f) const; virtual void build_sector_description(const format &d, uint8_t *sectdata, desc_s *sectors, int track, int head) const; void check_compatibility(floppy_image *image, std::vector<int> &candidates); diff --git a/src/lib/formats/vdk_dsk.cpp b/src/lib/formats/vdk_dsk.cpp index 57c44f8bb29..759697f852f 100644 --- a/src/lib/formats/vdk_dsk.cpp +++ b/src/lib/formats/vdk_dsk.cpp @@ -12,6 +12,9 @@ #include "vdk_dsk.h" +#include "ioprocs.h" + + vdk_format::vdk_format() { } @@ -31,10 +34,11 @@ const char *vdk_format::extensions() const return "vdk"; } -int vdk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int vdk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { + size_t actual; uint8_t id[2]; - io_generic_read(io, id, 0, 2); + io.read_at(0, id, 2, actual); if (id[0] == 'd' && id[1] == 'k') return 50; @@ -42,16 +46,21 @@ int vdk_format::identify(io_generic *io, uint32_t form_factor, const std::vector return 0; } -bool vdk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool vdk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { + size_t actual; + if (io.seek(0, SEEK_SET)) + return false; + uint8_t header[0x100]; - io_generic_read(io, header, 0, 0x100); + io.read(header, 0x100, actual); - int header_size = header[3] * 0x100 + header[2]; - int track_count = header[8]; - int head_count = header[9]; + int const header_size = header[3] * 0x100 + header[2]; + int const track_count = header[8]; + int const head_count = header[9]; - int file_offset = header_size; + if (io.seek(header_size, SEEK_SET)) + return false; for (int track = 0; track < track_count; track++) { @@ -72,10 +81,9 @@ bool vdk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui sectors[i].bad_crc = false; sectors[i].data = §or_data[sector_offset]; - io_generic_read(io, sectors[i].data, file_offset, SECTOR_SIZE); + io.read(sectors[i].data, SECTOR_SIZE, actual); sector_offset += SECTOR_SIZE; - file_offset += SECTOR_SIZE; } build_wd_track_mfm(track, head, image, 100000, SECTOR_COUNT, sectors, 22, 32, 24); @@ -85,9 +93,11 @@ bool vdk_format::load(io_generic *io, uint32_t form_factor, const std::vector<ui return true; } -bool vdk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool vdk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { - uint64_t file_offset = 0; + size_t actual; + if (io.seek(0, SEEK_SET)) + return false; int track_count, head_count; image->get_actual_geometry(track_count, head_count); @@ -108,8 +118,7 @@ bool vdk_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo header[10] = 0; header[11] = 0; - io_generic_write(io, header, file_offset, sizeof(header)); - file_offset += sizeof(header); + io.write(header, sizeof(header), actual); // write disk data for (int track = 0; track < track_count; track++) @@ -120,10 +129,7 @@ bool vdk_format::save(io_generic *io, const std::vector<uint32_t> &variants, flo auto sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); for (int i = 0; i < SECTOR_COUNT; i++) - { - io_generic_write(io, sectors[FIRST_SECTOR_ID + i].data(), file_offset, SECTOR_SIZE); - file_offset += SECTOR_SIZE; - } + io.write(sectors[FIRST_SECTOR_ID + i].data(), SECTOR_SIZE, actual); } } diff --git a/src/lib/formats/vdk_dsk.h b/src/lib/formats/vdk_dsk.h index 94347b326f6..797d2644972 100644 --- a/src/lib/formats/vdk_dsk.h +++ b/src/lib/formats/vdk_dsk.h @@ -25,9 +25,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; private: diff --git a/src/lib/formats/victor9k_dsk.cpp b/src/lib/formats/victor9k_dsk.cpp index ace1ec50933..3a142629726 100644 --- a/src/lib/formats/victor9k_dsk.cpp +++ b/src/lib/formats/victor9k_dsk.cpp @@ -99,6 +99,8 @@ #include "formats/victor9k_dsk.h" +#include "ioprocs.h" + victor9k_format::victor9k_format() { @@ -119,18 +121,22 @@ const char *victor9k_format::extensions() const return "img"; } -int victor9k_format::find_size(io_generic *io, uint32_t form_factor) +int victor9k_format::find_size(util::random_read &io, uint32_t form_factor) { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return -1; + for(int i=0; formats[i].sector_count; i++) { const format &f = formats[i]; if(size == (uint32_t) f.sector_count*f.sector_base_size*f.head_count) return i; } + return -1; } -int victor9k_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int victor9k_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { int type = find_size(io, form_factor); @@ -248,19 +254,24 @@ void victor9k_format::build_sector_description(const format &f, uint8_t *sectdat } } -bool victor9k_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool victor9k_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int type = find_size(io, form_factor); + int const type = find_size(io, form_factor); if(type == -1) return false; const format &f = formats[type]; - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; + std::vector<uint8_t> img; - img.resize(size); + try { img.resize(size); } + catch (...) { return false; } - io_generic_read(io, &img[0], 0, size); + size_t actual; + io.read_at(0, &img[0], size, actual); log_boot_sector(&img[0]); @@ -392,7 +403,7 @@ const int victor9k_format::rpm[9] = 252, 267, 283, 300, 321, 342, 368, 401, 417 }; -bool victor9k_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool victor9k_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { const format &f = formats[0]; @@ -406,7 +417,8 @@ bool victor9k_format::save(io_generic *io, const std::vector<uint32_t> &variants build_sector_description(f, sectdata, 0, sectors, sector_count); extract_sectors(image, f, sectors, track, head, sector_count); - io_generic_write(io, sectdata, offset, track_size); + size_t actual; + io.write_at(offset, sectdata, track_size, actual); } } diff --git a/src/lib/formats/victor9k_dsk.h b/src/lib/formats/victor9k_dsk.h index 92d1c664a5f..aafd8fdcb14 100644 --- a/src/lib/formats/victor9k_dsk.h +++ b/src/lib/formats/victor9k_dsk.h @@ -34,9 +34,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override { return true; } static int get_rpm(int head, int track); @@ -49,7 +49,7 @@ protected: static const int speed_zone[2][80]; static const int rpm[9]; - int find_size(io_generic *io, uint32_t form_factor); + int find_size(util::random_read &io, uint32_t form_factor); void log_boot_sector(uint8_t *data); floppy_image_format_t::desc_e* get_sector_desc(const format &f, int ¤t_size, int sector_count); void build_sector_description(const format &f, uint8_t *sectdata, uint32_t sect_offs, desc_s *sectors, int sector_count) const; diff --git a/src/lib/formats/vt_dsk.cpp b/src/lib/formats/vt_dsk.cpp index d6cc3da4521..15c6955bfcc 100644 --- a/src/lib/formats/vt_dsk.cpp +++ b/src/lib/formats/vt_dsk.cpp @@ -10,6 +10,9 @@ #include "formats/vt_dsk.h" +#include "ioprocs.h" + + // Zero = | 9187 | // One = | 2237 | 6950 | // 0.5us ~= 143 @@ -213,9 +216,11 @@ const char *vtech_dsk_format::extensions() const return "dsk"; } -int vtech_bin_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int vtech_bin_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; if(size == 40*16*256) return 50; @@ -223,14 +228,18 @@ int vtech_bin_format::identify(io_generic *io, uint32_t form_factor, const std:: return 0; } -int vtech_dsk_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int vtech_dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return 0; + if(size < 256) return 0; std::vector<uint8_t> bdata(size); - io_generic_read(io, bdata.data(), 0, size); + size_t actual; + io.read_at(0, bdata.data(), size, actual); // Structurally validate the presence of sector headers and data int count_sh = 0, count_sd = 0; @@ -246,25 +255,29 @@ int vtech_dsk_format::identify(io_generic *io, uint32_t form_factor, const std:: return count_sh >= 30*16 && count_sd >= 30*16 ? 100 : 0; } -bool vtech_bin_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool vtech_bin_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int size = io_generic_size(io); - if(size != 40*16*256) + uint64_t size; + if(io.length(size) || (size != 40*16*256)) return false; std::vector<uint8_t> bdata(size); - io_generic_read(io, bdata.data(), 0, size); + size_t actual; + io.read_at(0, bdata.data(), size, actual); image_to_flux(bdata, image); image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); return true; } -bool vtech_dsk_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return false; std::vector<uint8_t> bdata(size); - io_generic_read(io, bdata.data(), 0, size); + size_t actual; + io.read_at(0, bdata.data(), size, actual); std::vector<uint8_t> bdatax(128*16*40, 0); @@ -327,7 +340,7 @@ bool vtech_dsk_format::load(io_generic *io, uint32_t form_factor, const std::vec return true; } -bool vtech_bin_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool vtech_bin_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int tracks, heads; image->get_maximal_geometry(tracks, heads); @@ -335,11 +348,12 @@ bool vtech_bin_format::save(io_generic *io, const std::vector<uint32_t> &variant return false; auto bdata = flux_to_image(image); - io_generic_write(io, bdata.data(), 0, bdata.size()); + size_t actual; + io.write_at(0, bdata.data(), bdata.size(), actual); return true; } -bool vtech_dsk_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool vtech_dsk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { int tracks, heads; image->get_maximal_geometry(tracks, heads); @@ -387,7 +401,8 @@ bool vtech_dsk_format::save(io_generic *io, const std::vector<uint32_t> &variant } } - io_generic_write(io, bdatax.data(), 0, bdatax.size()); + size_t actual; + io.write_at(0, bdatax.data(), bdatax.size(), actual); return true; } diff --git a/src/lib/formats/vt_dsk.h b/src/lib/formats/vt_dsk.h index 739e5234a3f..4bc46871e7e 100644 --- a/src/lib/formats/vt_dsk.h +++ b/src/lib/formats/vt_dsk.h @@ -34,9 +34,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; }; class vtech_dsk_format : public vtech_common_format { @@ -47,9 +47,9 @@ public: virtual const char *description() const override; virtual const char *extensions() const override; - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; }; extern const floppy_format_type FLOPPY_VTECH_BIN_FORMAT; diff --git a/src/lib/formats/wd177x_dsk.cpp b/src/lib/formats/wd177x_dsk.cpp index 22309f32a12..da900b03db5 100644 --- a/src/lib/formats/wd177x_dsk.cpp +++ b/src/lib/formats/wd177x_dsk.cpp @@ -10,6 +10,8 @@ #include "formats/wd177x_dsk.h" +#include "ioprocs.h" + wd177x_format::wd177x_format(const format *_formats) { @@ -29,9 +31,12 @@ const wd177x_format::format &wd177x_format::get_track_format(const format &f, in /* Default implementation for find_size. May be overwritten by subclasses. */ -int wd177x_format::find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int wd177x_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - uint64_t size = io_generic_size(io); + uint64_t size; + if(io.length(size)) + return -1; + for(int i=0; formats[i].form_factor; i++) { const format &f = formats[i]; if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor) @@ -49,15 +54,17 @@ int wd177x_format::find_size(io_generic *io, uint32_t form_factor, const std::ve if(size == format_size) return i; } + return -1; } -int wd177x_format::identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) +int wd177x_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if(type != -1) return 50; + return 0; } @@ -197,9 +204,9 @@ floppy_image_format_t::desc_e* wd177x_format::get_desc_mfm(const format &f, int return desc; } -bool wd177x_format::load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) +bool wd177x_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if(type == -1) return false; @@ -251,7 +258,8 @@ bool wd177x_format::load(io_generic *io, uint32_t form_factor, const std::vector build_sector_description(tf, sectdata, sectors, track, head); int track_size = compute_track_size(tf); - io_generic_read(io, sectdata, get_image_offset(f, head, track), track_size); + size_t actual; + io.read_at(get_image_offset(f, head, track), sectdata, track_size, actual); generate_track(desc, track, head, sectors, tf.sector_count, total_size, image); } @@ -265,7 +273,7 @@ bool wd177x_format::supports_save() const return true; } -bool wd177x_format::save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) +bool wd177x_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) { // Count the number of formats int formats_count; @@ -377,7 +385,8 @@ bool wd177x_format::save(io_generic *io, const std::vector<uint32_t> &variants, build_sector_description(tf, sectdata, sectors, track, head); extract_sectors(image, tf, sectors, track, head); int track_size = compute_track_size(tf); - io_generic_write(io, sectdata, get_image_offset(f, head, track), track_size); + size_t actual; + io.write_at(get_image_offset(f, head, track), sectdata, track_size, actual); } } diff --git a/src/lib/formats/wd177x_dsk.h b/src/lib/formats/wd177x_dsk.h index 4cae9ffa754..a7bd92994e6 100644 --- a/src/lib/formats/wd177x_dsk.h +++ b/src/lib/formats/wd177x_dsk.h @@ -38,9 +38,9 @@ public: // End the array with {} wd177x_format(const format *formats); - virtual int identify(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; - virtual bool load(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; - virtual bool save(io_generic *io, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image *image) override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, floppy_image *image) override; virtual bool supports_save() const override; protected: @@ -51,7 +51,7 @@ protected: virtual const wd177x_format::format &get_track_format(const format &f, int head, int track); virtual floppy_image_format_t::desc_e* get_desc_fm(const format &f, int ¤t_size, int &end_gap_index); virtual floppy_image_format_t::desc_e* get_desc_mfm(const format &f, int ¤t_size, int &end_gap_index); - virtual int find_size(io_generic *io, uint32_t form_factor, const std::vector<uint32_t> &variants); + virtual int find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants); virtual int get_image_offset(const format &f, int head, int track); virtual int get_track_dam_fm(const format &f, int head, int track); virtual int get_track_dam_mfm(const format &f, int head, int track); diff --git a/src/lib/util/avhuff.cpp b/src/lib/util/avhuff.cpp index ac5cea71526..0689fe25b80 100644 --- a/src/lib/util/avhuff.cpp +++ b/src/lib/util/avhuff.cpp @@ -896,9 +896,9 @@ avhuff_error avhuff_decoder::decode_audio(int channels, int samples, const uint8 { // reset and decode if (!m_flac_decoder.reset(48000, 1, samples, source, size)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (!m_flac_decoder.decode_interleaved(reinterpret_cast<int16_t *>(curdest), samples, swap_endian)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // finish up m_flac_decoder.finish(); diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp index 03014611873..3a3a1a412f6 100644 --- a/src/lib/util/aviio.cpp +++ b/src/lib/util/aviio.cpp @@ -1710,8 +1710,8 @@ avi_file::error avi_file_impl::read_uncompressed_video_frame(std::uint32_t frame /* read in the data */ std::uint32_t bytes_read; - osd_file::error const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read); - if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(framenum).length) + std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read); + if (filerr || bytes_read != stream->chunk(framenum).length) return error::READ_ERROR; /* validate this is good data */ @@ -1765,8 +1765,8 @@ avi_file::error avi_file_impl::read_video_frame(std::uint32_t framenum, bitmap_y /* read in the data */ std::uint32_t bytes_read; - osd_file::error const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read); - if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(framenum).length) + std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(framenum).offset, stream->chunk(framenum).length, bytes_read); + if (filerr || bytes_read != stream->chunk(framenum).length) return error::READ_ERROR; /* validate this is good data */ @@ -1857,8 +1857,8 @@ avi_file::error avi_file_impl::read_sound_samples(int channel, std::uint32_t fir return avierr; /* read in the data */ - auto const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(chunknum).offset, stream->chunk(chunknum).length, bytes_read); - if (filerr != osd_file::error::NONE || bytes_read != stream->chunk(chunknum).length) + std::error_condition const filerr = m_file->read(&m_tempbuffer[0], stream->chunk(chunknum).offset, stream->chunk(chunknum).length, bytes_read); + if (filerr || bytes_read != stream->chunk(chunknum).length) return error::READ_ERROR; /* validate this is good data */ @@ -2085,14 +2085,15 @@ avi_file::error avi_file_impl::append_sound_samples(int channel, const std::int1 avi_file::error avi_file_impl::read_chunk_data(avi_chunk const &chunk, std::unique_ptr<std::uint8_t []> &buffer) { - /* allocate memory for the data */ - try { buffer.reset(new std::uint8_t[chunk.size]); } - catch (...) { return error::NO_MEMORY; } + // allocate memory for the data + buffer.reset(new (std::nothrow) std::uint8_t[chunk.size]); + if (!buffer) + return error::NO_MEMORY; - /* read from the file */ + // read from the file std::uint32_t bytes_read; - osd_file::error const filerr = m_file->read(&buffer[0], chunk.offset + 8, chunk.size, bytes_read); - if (filerr != osd_file::error::NONE || bytes_read != chunk.size) + std::error_condition const filerr = m_file->read(&buffer[0], chunk.offset + 8, chunk.size, bytes_read); + if (filerr || bytes_read != chunk.size) { buffer.reset(); return error::READ_ERROR; @@ -2292,35 +2293,33 @@ avi_file::error avi_file_impl::find_next_list(std::uint32_t findme, const avi_ch avi_file::error avi_file_impl::get_next_chunk_internal(const avi_chunk *parent, avi_chunk &newchunk, std::uint64_t offset) { - osd_file::error filerr; - std::uint8_t buffer[12]; - std::uint32_t bytesread; - - /* nullptr parent implies the root */ - if (parent == nullptr) + // nullptr parent implies the root + if (!parent) parent = &m_rootchunk; - /* start at the current offset */ + // start at the current offset newchunk.offset = offset; - /* if we're past the bounds of the parent, bail */ + // if we're past the bounds of the parent, bail if (newchunk.offset + 8 >= parent->offset + 8 + parent->size) return error::END; - /* read the header */ - filerr = m_file->read(buffer, newchunk.offset, 8, bytesread); - if (filerr != osd_file::error::NONE || bytesread != 8) + // read the header + std::uint8_t buffer[12]; + std::uint32_t bytesread; + std::error_condition filerr = m_file->read(buffer, newchunk.offset, 8, bytesread); + if (filerr || bytesread != 8) return error::INVALID_DATA; - /* fill in the new chunk */ + // fill in the new chunk newchunk.type = fetch_32bits(&buffer[0]); newchunk.size = fetch_32bits(&buffer[4]); - /* if we are a list, fetch the list type */ + // if we are a list, fetch the list type if (newchunk.type == CHUNKTYPE_LIST || newchunk.type == CHUNKTYPE_RIFF) { filerr = m_file->read(&buffer[8], newchunk.offset + 8, 4, bytesread); - if (filerr != osd_file::error::NONE || bytesread != 4) + if (filerr || bytesread != 4) return error::INVALID_DATA; newchunk.listtype = fetch_32bits(&buffer[8]); } @@ -2643,16 +2642,15 @@ avi_file::error avi_file_impl::parse_indx_chunk(avi_stream &stream, avi_chunk co /* loop over entries and create subchunks for each */ for (std::uint32_t entry = 0; entry < entries; entry++) { - const std::uint8_t *base = &chunkdata[24 + entry * 16]; - osd_file::error filerr; + std::uint8_t const *const base = &chunkdata[24 + entry * 16]; avi_chunk subchunk; - std::uint32_t bytes_read; - std::uint8_t buffer[8]; /* go read the subchunk */ subchunk.offset = fetch_64bits(&base[0]); - filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read); - if (filerr != osd_file::error::NONE || bytes_read != sizeof(buffer)) + std::uint32_t bytes_read; + std::uint8_t buffer[8]; + std::error_condition const filerr = m_file->read(buffer, subchunk.offset, sizeof(buffer), bytes_read); + if (filerr || bytes_read != sizeof(buffer)) { avierr = error::READ_ERROR; break; @@ -2788,8 +2786,8 @@ avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t list /* write the header */ std::uint32_t written; - osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written); - if (filerr != osd_file::error::NONE || written != sizeof(buffer)) + std::error_condition const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written); + if (filerr || written != sizeof(buffer)) return error::WRITE_ERROR; m_writeoffs += written; } @@ -2806,8 +2804,8 @@ avi_file::error avi_file_impl::chunk_open(std::uint32_t type, std::uint32_t list /* write the header */ std::uint32_t written; - osd_file::error const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written); - if (filerr != osd_file::error::NONE || written != sizeof(buffer)) + std::error_condition const filerr = m_file->write(buffer, m_writeoffs, sizeof(buffer), written); + if (filerr || written != sizeof(buffer)) return error::WRITE_ERROR; m_writeoffs += written; } @@ -2846,8 +2844,8 @@ avi_file::error avi_file_impl::chunk_close() put_32bits(&buffer[0], std::uint32_t(chunksize)); std::uint32_t written; - osd_file::error const filerr = m_file->write(buffer, chunk.offset + 4, sizeof(buffer), written); - if (filerr != osd_file::error::NONE || written != sizeof(buffer)) + std::error_condition const filerr = m_file->write(buffer, chunk.offset + 4, sizeof(buffer), written); + if (filerr || written != sizeof(buffer)) return error::WRITE_ERROR; } @@ -2925,8 +2923,8 @@ avi_file::error avi_file_impl::chunk_write(std::uint32_t type, const void *data, /* write the data */ std::uint32_t written; - osd_file::error const filerr = m_file->write(data, m_writeoffs, length, written); - if (filerr != osd_file::error::NONE || written != length) + std::error_condition const filerr = m_file->write(data, m_writeoffs, length, written); + if (filerr || written != length) return error::WRITE_ERROR; m_writeoffs += written; @@ -3678,7 +3676,7 @@ avi_file::error avi_file::open(std::string const &filename, ptr &file) /* open the file */ osd_file::ptr f; std::uint64_t length; - if (osd_file::open(filename, OPEN_FLAG_READ, f, length) != osd_file::error::NONE) + if (osd_file::open(filename, OPEN_FLAG_READ, f, length)) return error::CANT_OPEN_FILE; /* allocate the file */ @@ -3731,8 +3729,8 @@ avi_file::error avi_file::create(std::string const &filename, movie_info const & /* open the file */ osd_file::ptr f; std::uint64_t length; - osd_file::error const filerr = osd_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, f, length); - if (filerr != osd_file::error::NONE) + std::error_condition const filerr = osd_file::open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, f, length); + if (filerr) return error::CANT_OPEN_FILE; /* allocate the file */ diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp index 4ac1ab6e865..7510a1f9b47 100644 --- a/src/lib/util/cdrom.cpp +++ b/src/lib/util/cdrom.cpp @@ -19,6 +19,7 @@ #include "cdrom.h" #include "chdcd.h" +#include "corefile.h" #include <cassert> #include <cstdlib> @@ -223,10 +224,10 @@ cdrom_file *cdrom_open(const char *inputfile) return nullptr; // set up the CD-ROM module and get the disc info - chd_error err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info); - if (err != CHDERR_NONE) + std::error_condition err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info); + if (err) { - fprintf(stderr, "Error reading input file: %s\n", chd_file::error_string(err)); + fprintf(stderr, "Error reading input file: %s\n", err.message().c_str()); delete file; return nullptr; } @@ -238,14 +239,15 @@ cdrom_file *cdrom_open(const char *inputfile) for (i = 0; i < file->cdtoc.numtrks; i++) { - osd_file::error filerr = util::core_file::open(file->track_info.track[i].fname, OPEN_FLAG_READ, file->fhandle[i]); - if (filerr != osd_file::error::NONE) + std::error_condition const filerr = util::core_file::open(file->track_info.track[i].fname, OPEN_FLAG_READ, file->fhandle[i]); + if (filerr) { fprintf(stderr, "Unable to open file: %s\n", file->track_info.track[i].fname.c_str()); cdrom_close(file); return nullptr; } } + /* calculate the starting frame for each track, keeping in mind that CHDMAN pads tracks out with extra frames to fit 4-frame size boundries */ @@ -336,8 +338,8 @@ cdrom_file *cdrom_open(chd_file *chd) file->chd = chd; /* read the CD-ROM metadata */ - chd_error err = cdrom_parse_metadata(chd, &file->cdtoc); - if (err != CHDERR_NONE) + std::error_condition err = cdrom_parse_metadata(chd, &file->cdtoc); + if (err) { delete file; return nullptr; @@ -446,7 +448,7 @@ void cdrom_close(cdrom_file *file) ***************************************************************************/ /** - * @fn chd_error read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length) + * @fn std::error_condition read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length) * * @brief Reads partial sector. * @@ -461,9 +463,9 @@ void cdrom_close(cdrom_file *file) * @return The partial sector. */ -chd_error read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length, bool phys=false) +std::error_condition read_partial_sector(cdrom_file *file, void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length, bool phys=false) { - chd_error result = CHDERR_NONE; + std::error_condition result; bool needswap = false; // if this is pregap info that isn't actually in the file, just return blank data @@ -570,14 +572,14 @@ uint32_t cdrom_read_data(cdrom_file *file, uint32_t lbasector, void *buffer, uin if ((datatype == tracktype) || (datatype == CD_TRACK_RAW_DONTCARE)) { - return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 0, file->cdtoc.tracks[tracknum].datasize, phys) == CHDERR_NONE); + return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 0, file->cdtoc.tracks[tracknum].datasize, phys); } else { // return 2048 bytes of mode 1 data from a 2352 byte mode 1 raw sector if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE1_RAW)) { - return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2048, phys) == CHDERR_NONE); + return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2048, phys); } // return 2352 byte mode 1 raw sector from 2048 bytes of mode 1 data @@ -593,25 +595,25 @@ uint32_t cdrom_read_data(cdrom_file *file, uint32_t lbasector, void *buffer, uin bufptr[14] = msf&0xff; bufptr[15] = 1; // mode 1 LOG(("CDROM: promotion of mode1/form1 sector to mode1 raw is not complete!\n")); - return (read_partial_sector(file, bufptr+16, lbasector, chdsector, tracknum, 0, 2048, phys) == CHDERR_NONE); + return !read_partial_sector(file, bufptr+16, lbasector, chdsector, tracknum, 0, 2048, phys); } // return 2048 bytes of mode 1 data from a mode2 form1 or raw sector if ((datatype == CD_TRACK_MODE1) && ((tracktype == CD_TRACK_MODE2_FORM1)||(tracktype == CD_TRACK_MODE2_RAW))) { - return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 24, 2048, phys) == CHDERR_NONE); + return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 24, 2048, phys); } // return 2048 bytes of mode 1 data from a mode2 form2 or XA sector if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE2_FORM_MIX)) { - return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 8, 2048, phys) == CHDERR_NONE); + return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 8, 2048, phys); } // return mode 2 2336 byte data from a 2352 byte mode 1 or 2 raw sector (skip the header) if ((datatype == CD_TRACK_MODE2) && ((tracktype == CD_TRACK_MODE1_RAW) || (tracktype == CD_TRACK_MODE2_RAW))) { - return (read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2336, phys) == CHDERR_NONE); + return !read_partial_sector(file, buffer, lbasector, chdsector, tracknum, 16, 2336, phys); } LOG(("CDROM: Conversion from type %d to type %d not supported!\n", tracktype, datatype)); @@ -660,8 +662,8 @@ uint32_t cdrom_read_subcode(cdrom_file *file, uint32_t lbasector, void *buffer, return 0; // read the data - chd_error err = read_partial_sector(file, buffer, lbasector, chdsector, tracknum, file->cdtoc.tracks[tracknum].datasize, file->cdtoc.tracks[tracknum].subsize); - return (err == CHDERR_NONE); + std::error_condition err = read_partial_sector(file, buffer, lbasector, chdsector, tracknum, file->cdtoc.tracks[tracknum].datasize, file->cdtoc.tracks[tracknum].subsize); + return !err; } @@ -1139,21 +1141,20 @@ const char *cdrom_get_subtype_string(uint32_t subtype) -------------------------------------------------*/ /** - * @fn chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) + * @fn std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) * * @brief Cdrom parse metadata. * * @param [in,out] chd If non-null, the chd. * @param [in,out] toc If non-null, the TOC. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) +std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) { std::string metadata; - chd_error err; - int i; + std::error_condition err; toc->flags = 0; @@ -1168,49 +1169,49 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) /* fetch the metadata for this track */ err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata); - if (err == CHDERR_NONE) + if (!err) { /* parse the metadata */ type[0] = subtype[0] = 0; pgtype[0] = pgsub[0] = 0; if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames) != 4) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; if (tracknum == 0 || tracknum > CD_MAX_TRACKS) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; track = &toc->tracks[tracknum - 1]; } else { err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc->numtrks, metadata); - if (err == CHDERR_NONE) + if (!err) { /* parse the metadata */ type[0] = subtype[0] = 0; pregap = postgap = 0; if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; if (tracknum == 0 || tracknum > CD_MAX_TRACKS) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; track = &toc->tracks[tracknum - 1]; } else { err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc->numtrks, metadata); - if (err == CHDERR_NONE) + if (!err) /* legacy GDROM track was detected */ toc->flags |= CD_FLAG_GDROMLE; else err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc->numtrks, metadata); - if (err == CHDERR_NONE) + if (!err) { /* parse the metadata */ type[0] = subtype[0] = 0; pregap = postgap = 0; if (sscanf(metadata.c_str(), GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; if (tracknum == 0 || tracknum > CD_MAX_TRACKS) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; track = &toc->tracks[tracknum - 1]; toc->flags |= CD_FLAG_GDROM; } @@ -1226,7 +1227,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) track->datasize = 0; cdrom_convert_type_string_to_track_info(type, track); if (track->datasize == 0) - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; /* extract the subtype and determine the subcode data size */ track->subtype = CD_SUB_NONE; @@ -1261,21 +1262,21 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) /* if we got any tracks this way, we're done */ if (toc->numtrks > 0) - return CHDERR_NONE; + return std::error_condition(); printf("toc->numtrks = %u?!\n", toc->numtrks); /* look for old-style metadata */ std::vector<uint8_t> oldmetadata; err = chd->read_metadata(CDROM_OLD_METADATA_TAG, 0, oldmetadata); - if (err != CHDERR_NONE) + if (err) return err; /* reconstruct the TOC from it */ auto *mrp = reinterpret_cast<uint32_t *>(&oldmetadata[0]); toc->numtrks = *mrp++; - for (i = 0; i < CD_MAX_TRACKS; i++) + for (int i = 0; i < CD_MAX_TRACKS; i++) { toc->tracks[i].trktype = *mrp++; toc->tracks[i].subtype = *mrp++; @@ -1295,7 +1296,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) if (toc->numtrks > CD_MAX_TRACKS) { toc->numtrks = swapendian_int32(toc->numtrks); - for (i = 0; i < CD_MAX_TRACKS; i++) + for (int i = 0; i < CD_MAX_TRACKS; i++) { toc->tracks[i].trktype = swapendian_int32(toc->tracks[i].trktype); toc->tracks[i].subtype = swapendian_int32(toc->tracks[i].subtype); @@ -1307,7 +1308,7 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) } } - return CHDERR_NONE; + return std::error_condition(); } @@ -1316,19 +1317,19 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) -------------------------------------------------*/ /** - * @fn chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc) + * @fn std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc) * * @brief Cdrom write metadata. * * @param [in,out] chd If non-null, the chd. * @param toc The TOC. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc) +std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc) { - chd_error err; + std::error_condition err; /* write the metadata */ for (int i = 0; i < toc->numtrks; i++) @@ -1363,10 +1364,10 @@ chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc) err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata); } - if (err != CHDERR_NONE) + if (err) return err; } - return CHDERR_NONE; + return std::error_condition(); } /** diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h index 27d41da845e..1847a1db83a 100644 --- a/src/lib/util/cdrom.h +++ b/src/lib/util/cdrom.h @@ -7,15 +7,15 @@ Generic MAME cd-rom implementation ***************************************************************************/ - -#ifndef MAME_UTIL_CDROM_H -#define MAME_UTIL_CDROM_H +#ifndef MAME_LIB_UTIL_CDROM_H +#define MAME_LIB_UTIL_CDROM_H #pragma once -#include "osdcore.h" #include "chd.h" +#include "osdcore.h" + /*************************************************************************** @@ -137,8 +137,8 @@ void cdrom_convert_subtype_string_to_track_info(const char *typestring, cdrom_tr void cdrom_convert_subtype_string_to_pregap_info(const char *typestring, cdrom_track_info *info); const char *cdrom_get_type_string(uint32_t trktype); const char *cdrom_get_subtype_string(uint32_t subtype); -chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc); -chd_error cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc); +std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc); +std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc); // ECC utilities bool ecc_verify(const uint8_t *sector); @@ -184,4 +184,4 @@ static inline uint32_t lba_to_msf_alt(int lba) return ret; } -#endif // MAME_UTIL_CDROM_H +#endif // MAME_LIB_UTIL_CDROM_H diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp index 0de05849cdd..29792fc36df 100644 --- a/src/lib/util/chd.cpp +++ b/src/lib/util/chd.cpp @@ -8,20 +8,24 @@ ***************************************************************************/ -#include <cassert> - #include "chd.h" + #include "avhuff.h" -#include "hashing.h" -#include "flac.h" #include "cdrom.h" +#include "corefile.h" #include "coretmpl.h" +#include "flac.h" +#include "hashing.h" + +#include "eminline.h" + #include <zlib.h> -#include <ctime> + +#include <cassert> #include <cstddef> #include <cstdlib> +#include <ctime> #include <new> -#include "eminline.h" //************************************************************************** @@ -186,14 +190,17 @@ inline void chd_file::be_write_sha1(uint8_t *base, util::sha1_t value) inline void chd_file::file_read(uint64_t offset, void *dest, uint32_t length) { // no file = failure - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // seek and read m_file->seek(offset, SEEK_SET); - uint32_t count = m_file->read(dest, length); - if (count != length) - throw CHDERR_READ_ERROR; + size_t count; + std::error_condition err = m_file->read(dest, length, count); + if (err) + throw err; + else if (count != length) + throw std::error_condition(std::errc::io_error); // TODO: revisit this error code (happens if file is cut off) } @@ -205,14 +212,17 @@ inline void chd_file::file_read(uint64_t offset, void *dest, uint32_t length) inline void chd_file::file_write(uint64_t offset, const void *source, uint32_t length) { // no file = failure - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // seek and write m_file->seek(offset, SEEK_SET); - uint32_t count = m_file->write(source, length); - if (count != length) - throw CHDERR_WRITE_ERROR; + size_t count; + std::error_condition err = m_file->write(source, length, count); + if (err) + throw err; + else if (count != length) + throw std::error_condition(std::errc::interrupted); // can theoretically happen if write is inuterrupted by a signal } @@ -224,15 +234,22 @@ inline void chd_file::file_write(uint64_t offset, const void *source, uint32_t l inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint32_t alignment) { + std::error_condition err; + // no file = failure - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // seek to the end and align if necessary - m_file->seek(0, SEEK_END); + err = m_file->seek(0, SEEK_END); + if (err) + throw err; if (alignment != 0) { - uint64_t offset = m_file->tell(); + uint64_t offset; + err = m_file->tell(offset); + if (err) + throw err; uint32_t delta = offset % alignment; if (delta != 0) { @@ -242,20 +259,27 @@ inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint3 delta = alignment - delta; while (delta != 0) { - uint32_t bytes_to_write = (std::min<std::size_t>)(sizeof(buffer), delta); - uint32_t count = m_file->write(buffer, bytes_to_write); - if (count != bytes_to_write) - throw CHDERR_WRITE_ERROR; - delta -= bytes_to_write; + uint32_t bytes_to_write = std::min<std::size_t>(sizeof(buffer), delta); + size_t count; + err = m_file->write(buffer, bytes_to_write, count); + if (err) + throw err; + delta -= count; } } } // write the real data - uint64_t offset = m_file->tell(); - uint32_t count = m_file->write(source, length); - if (count != length) - throw CHDERR_READ_ERROR; + uint64_t offset; + err = m_file->tell(offset); + if (err) + throw err; + size_t count; + err = m_file->write(source, length, count); + if (err) + throw err; + else if (count != length) + throw std::error_condition(std::errc::interrupted); // can theoretically happen if write is interrupted by a signal return offset; } @@ -288,11 +312,8 @@ inline uint8_t chd_file::bits_for_value(uint64_t value) */ chd_file::chd_file() - : m_file(nullptr), - m_owns_file(false) { // reset state - memset(m_decompressor, 0, sizeof(m_decompressor)); close(); } @@ -311,6 +332,22 @@ chd_file::~chd_file() } /** + * @fn util::random_read chd_file::file() + * + * @brief ------------------------------------------------- + * file - return our underlying file + * -------------------------------------------------. + * + * @return A random_read. + */ + +util::random_read &chd_file::file() +{ + assert(m_file); + return *m_file; +} + +/** * @fn util::sha1_t chd_file::sha1() * * @brief ------------------------------------------------- @@ -329,7 +366,7 @@ util::sha1_t chd_file::sha1() file_read(m_sha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } - catch (chd_error &) + catch (std::error_condition const &) { // on failure, return nullptr return util::sha1_t::null; @@ -354,15 +391,15 @@ util::sha1_t chd_file::raw_sha1() try { // determine offset within the file for data-only - if (m_rawsha1_offset == 0) - throw CHDERR_UNSUPPORTED_VERSION; + if (!m_rawsha1_offset) + throw std::error_condition(error::UNSUPPORTED_VERSION); // read the big-endian version uint8_t rawbuf[sizeof(util::sha1_t)]; file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } - catch (chd_error &) + catch (std::error_condition const &) { // on failure, return nullptr return util::sha1_t::null; @@ -387,15 +424,15 @@ util::sha1_t chd_file::parent_sha1() try { // determine offset within the file - if (m_parentsha1_offset == 0) - throw CHDERR_UNSUPPORTED_VERSION; + if (!m_parentsha1_offset) + throw std::error_condition(error::UNSUPPORTED_VERSION); // read the big-endian version uint8_t rawbuf[sizeof(util::sha1_t)]; file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } - catch (chd_error &) + catch (std::error_condition const &) { // on failure, return nullptr return util::sha1_t::null; @@ -403,7 +440,7 @@ util::sha1_t chd_file::parent_sha1() } /** - * @fn chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes) + * @fn std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes) * * @brief ------------------------------------------------- * hunk_info - return information about this hunk @@ -413,14 +450,14 @@ util::sha1_t chd_file::parent_sha1() * @param [in,out] compressor The compressor. * @param [in,out] compbytes The compbytes. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes) +std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes) { // error if invalid if (hunknum >= m_hunkcount) - return CHDERR_HUNK_OUT_OF_RANGE; + return std::error_condition(error::HUNK_OUT_OF_RANGE); // get the map pointer uint8_t *rawmap; @@ -506,11 +543,11 @@ chd_error chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint break; default: - return CHDERR_UNKNOWN_COMPRESSION; + return error::UNKNOWN_COMPRESSION; } break; } - return CHDERR_NONE; + return std::error_condition(); } /** @@ -554,8 +591,8 @@ void chd_file::set_raw_sha1(util::sha1_t rawdata) void chd_file::set_parent_sha1(util::sha1_t parent) { // if no file, fail - if (m_file == nullptr) - throw CHDERR_INVALID_FILE; + if (!m_file) + throw std::error_condition(error::INVALID_FILE); // create a big-endian version uint8_t rawbuf[sizeof(util::sha1_t)]; @@ -567,7 +604,7 @@ void chd_file::set_parent_sha1(util::sha1_t parent) } /** - * @fn chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) + * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) * * @brief ------------------------------------------------- * create - create a new file with no parent using an existing opened file handle @@ -579,14 +616,16 @@ void chd_file::set_parent_sha1(util::sha1_t parent) * @param unitbytes The unitbytes. * @param compression The compression. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) +std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; + else if (!file) + return std::errc::invalid_argument; // set the header parameters m_logicalbytes = logicalbytes; @@ -596,13 +635,12 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_ m_parent = nullptr; // take ownership of the file - m_file = &file; - m_owns_file = false; + m_file = std::move(file); return create_common(); } /** - * @fn chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) + * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) * * @brief ------------------------------------------------- * create - create a new file with a parent using an existing opened file handle @@ -614,14 +652,16 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_ * @param compression The compression. * @param [in,out] parent The parent. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) +std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; + else if (!file) + return std::errc::invalid_argument; // set the header parameters m_logicalbytes = logicalbytes; @@ -631,13 +671,12 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_ m_parent = &parent; // take ownership of the file - m_file = &file; - m_owns_file = false; + m_file = std::move(file); return create_common(); } /** - * @fn chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) + * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) * * @brief ------------------------------------------------- * create - create a new file with no parent using a filename @@ -649,40 +688,38 @@ chd_error chd_file::create(util::core_file &file, uint64_t logicalbytes, uint32_ * @param unitbytes The unitbytes. * @param compression The compression. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) +std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; // create the new file util::core_file::ptr file; - const osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != osd_file::error::NONE) - return CHDERR_FILE_NOT_FOUND; + std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); + if (filerr) + return filerr; + util::random_read_write::ptr io = util::core_file_read_write(std::move(file)); + if (!io) + return std::errc::not_enough_memory; // create the file normally, then claim the file - const chd_error chderr = create(*file, logicalbytes, hunkbytes, unitbytes, compression); - m_owns_file = true; + std::error_condition chderr = create(std::move(io), logicalbytes, hunkbytes, unitbytes, compression); // if an error happened, close and delete the file - if (chderr != CHDERR_NONE) + if (chderr) { - file.reset(); - osd_file::remove(filename); - } - else - { - file.release(); + io.reset(); + osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view } return chderr; } /** - * @fn chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) + * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) * * @brief ------------------------------------------------- * create - create a new file with a parent using a filename @@ -694,40 +731,38 @@ chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t * @param compression The compression. * @param [in,out] parent The parent. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) +std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; // create the new file util::core_file::ptr file; - const osd_file::error filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr != osd_file::error::NONE) - return CHDERR_FILE_NOT_FOUND; + std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); + if (filerr) + return filerr; + util::random_read_write::ptr io = util::core_file_read_write(std::move(file)); + if (!io) + return std::errc::not_enough_memory; // create the file normally, then claim the file - const chd_error chderr = create(*file, logicalbytes, hunkbytes, compression, parent); - m_owns_file = true; + std::error_condition chderr = create(std::move(io), logicalbytes, hunkbytes, compression, parent); // if an error happened, close and delete the file - if (chderr != CHDERR_NONE) - { - file.reset(); - osd_file::remove(filename); - } - else + if (chderr) { - file.release(); + io.reset(); + osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view } return chderr; } /** - * @fn chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent) + * @fn std::error_condition chd_file::open(std::string_view filename, bool writeable, chd_file *parent) * * @brief ------------------------------------------------- * open - open an existing file for read or read/write @@ -737,35 +772,36 @@ chd_error chd_file::create(const char *filename, uint64_t logicalbytes, uint32_t * @param writeable true if writeable. * @param [in,out] parent If non-null, the parent. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent) +std::error_condition chd_file::open(std::string_view filename, bool writeable, chd_file *parent) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; // open the file const uint32_t openflags = writeable ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_READ; util::core_file::ptr file; - const osd_file::error filerr = util::core_file::open(filename, openflags, file); - if (filerr != osd_file::error::NONE) - return CHDERR_FILE_NOT_FOUND; + std::error_condition filerr = util::core_file::open(filename, openflags, file); + if (filerr) + return filerr; + util::random_read_write::ptr io = util::core_file_read_write(std::move(file)); + if (!io) + return std::errc::not_enough_memory; // now open the CHD - chd_error err = open(*file, writeable, parent); - if (err != CHDERR_NONE) + std::error_condition err = open(std::move(io), writeable, parent); + if (err) return err; // we now own this file - file.release(); - m_owns_file = true; return err; } /** - * @fn chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent) + * @fn std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool writeable, chd_file *parent) * * @brief ------------------------------------------------- * open - open an existing file for read or read/write @@ -775,18 +811,19 @@ chd_error chd_file::open(const char *filename, bool writeable, chd_file *parent) * @param writeable true if writeable. * @param [in,out] parent If non-null, the parent. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent) +std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool writeable, chd_file *parent) { // make sure we don't already have a file open - if (m_file != nullptr) - return CHDERR_ALREADY_OPEN; + if (m_file) + return error::ALREADY_OPEN; + else if (!file) + return std::errc::invalid_argument; // open the file - m_file = &file; - m_owns_file = false; + m_file = std::move(file); m_parent = parent; m_cachehunk = ~0; return open_common(writeable); @@ -803,10 +840,7 @@ chd_error chd_file::open(util::core_file &file, bool writeable, chd_file *parent void chd_file::close() { // reset file characteristics - if (m_owns_file && m_file) - delete m_file; - m_file = nullptr; - m_owns_file = false; + m_file.reset(); m_allow_reads = false; m_allow_writes = false; @@ -836,10 +870,7 @@ void chd_file::close() // reset compression management for (auto & elem : m_decompressor) - { - delete elem; - elem = nullptr; - } + elem.reset(); m_compressed.clear(); // reset caching @@ -848,7 +879,7 @@ void chd_file::close() } /** - * @fn chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) + * @fn std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer) * * @brief ------------------------------------------------- * read - read a single hunk from the CHD file @@ -870,18 +901,18 @@ void chd_file::close() * @return The hunk. */ -chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) +std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer) { // wrap this for clean reporting try { // punt if no file - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // return an error if out of range if (hunknum >= m_hunkcount) - throw CHDERR_HUNK_OUT_OF_RANGE; + throw std::error_condition(error::HUNK_OUT_OF_RANGE); // get a pointer to the map entry uint64_t blockoffs; @@ -904,29 +935,29 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) file_read(blockoffs, &m_compressed[0], blocklen); m_decompressor[0]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes); if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != nullptr && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; + throw std::error_condition(error::DECOMPRESSION_ERROR); + return std::error_condition(); case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: file_read(blockoffs, dest, m_hunkbytes); if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; + throw std::error_condition(error::DECOMPRESSION_ERROR); + return std::error_condition(); case V34_MAP_ENTRY_TYPE_MINI: be_write(dest, blockoffs, 8); for (uint32_t bytes = 8; bytes < m_hunkbytes; bytes++) dest[bytes] = dest[bytes - 8]; if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; + throw std::error_condition(error::DECOMPRESSION_ERROR); + return std::error_condition(); case V34_MAP_ENTRY_TYPE_SELF_HUNK: return read_hunk(blockoffs, dest); case V34_MAP_ENTRY_TYPE_PARENT_HUNK: if (m_parent_missing) - throw CHDERR_REQUIRES_PARENT; + throw std::error_condition(error::REQUIRES_PARENT); return m_parent->read_hunk(blockoffs, dest); } break; @@ -942,12 +973,12 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) if (blockoffs != 0) file_read(blockoffs, dest, m_hunkbytes); else if (m_parent_missing) - throw CHDERR_REQUIRES_PARENT; + throw std::error_condition(error::REQUIRES_PARENT); else if (m_parent != nullptr) m_parent->read_hunk(hunknum, dest); else memset(dest, 0, m_hunkbytes); - return CHDERR_NONE; + return std::error_condition(); } // compressed case @@ -963,41 +994,40 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) file_read(blockoffs, &m_compressed[0], blocklen); m_decompressor[rawmap[0]]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes); if (!m_decompressor[rawmap[0]]->lossy() && dest != nullptr && util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(error::DECOMPRESSION_ERROR); if (m_decompressor[rawmap[0]]->lossy() && util::crc16_creator::simple(&m_compressed[0], blocklen) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; + throw std::error_condition(error::DECOMPRESSION_ERROR); + return std::error_condition(); case COMPRESSION_NONE: file_read(blockoffs, dest, m_hunkbytes); if (util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc) - throw CHDERR_DECOMPRESSION_ERROR; - return CHDERR_NONE; + throw std::error_condition(error::DECOMPRESSION_ERROR); + return std::error_condition(); case COMPRESSION_SELF: return read_hunk(blockoffs, dest); case COMPRESSION_PARENT: if (m_parent_missing) - throw CHDERR_REQUIRES_PARENT; + throw std::error_condition(error::REQUIRES_PARENT); return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); } break; } // if we get here, something was wrong - throw CHDERR_READ_ERROR; + throw std::error_condition(std::errc::io_error); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer) + * @fn std::error_condition chd_file::write_hunk(uint32_t hunknum, const void *buffer) * * @brief ------------------------------------------------- * write - write a single hunk to the CHD file @@ -1012,29 +1042,29 @@ chd_error chd_file::read_hunk(uint32_t hunknum, void *buffer) * @param hunknum The hunknum. * @param buffer The buffer. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer) +std::error_condition chd_file::write_hunk(uint32_t hunknum, const void *buffer) { // wrap this for clean reporting try { // punt if no file - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // return an error if out of range if (hunknum >= m_hunkcount) - throw CHDERR_HUNK_OUT_OF_RANGE; + throw std::error_condition(error::HUNK_OUT_OF_RANGE); // if not writeable, fail if (!m_allow_writes) - throw CHDERR_FILE_NOT_WRITEABLE; + throw std::error_condition(error::FILE_NOT_WRITEABLE); // uncompressed writes only via this interface if (compressed()) - throw CHDERR_FILE_NOT_WRITEABLE; + throw std::error_condition(error::FILE_NOT_WRITEABLE); // see if we have allocated the space on disk for this hunk uint8_t *rawmap = &m_rawmap[hunknum * 4]; @@ -1055,7 +1085,7 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer) // if it's all zeros, do nothing more if (all_zeros) - return CHDERR_NONE; + return std::error_condition(); // append new data to the end of the file, aligning the first chunk rawentry = file_append(buffer, m_hunkbytes, m_hunkbytes) / m_hunkbytes; @@ -1068,22 +1098,22 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer) if (hunknum == m_cachehunk && buffer != &m_cache[0]) memcpy(&m_cache[0], buffer, m_hunkbytes); } - - // otherwise, just overwrite else + { + // otherwise, just overwrite file_write(uint64_t(rawentry) * uint64_t(m_hunkbytes), buffer, m_hunkbytes); - return CHDERR_NONE; + } + return std::error_condition(); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count) + * @fn std::error_condition chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count) * * @brief ------------------------------------------------- * read_units - read the given number of units from the CHD @@ -1096,13 +1126,13 @@ chd_error chd_file::write_hunk(uint32_t hunknum, const void *buffer) * @return The units. */ -chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count) +std::error_condition chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count) { return read_bytes(unitnum * uint64_t(m_unitbytes), buffer, count * m_unitbytes); } /** - * @fn chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count) + * @fn std::error_condition chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count) * * @brief ------------------------------------------------- * write_units - write the given number of units to the CHD @@ -1112,16 +1142,16 @@ chd_error chd_file::read_units(uint64_t unitnum, void *buffer, uint32_t count) * @param buffer The buffer. * @param count Number of. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count) +std::error_condition chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t count) { return write_bytes(unitnum * uint64_t(m_unitbytes), buffer, count * m_unitbytes); } /** - * @fn chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) + * @fn std::error_condition chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) * * @brief ------------------------------------------------- * read_bytes - read from the CHD at a byte level, using the cache to handle partial @@ -1135,7 +1165,7 @@ chd_error chd_file::write_units(uint64_t unitnum, const void *buffer, uint32_t c * @return The bytes. */ -chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) +std::error_condition chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) { // iterate over hunks uint32_t first_hunk = offset / m_hunkbytes; @@ -1148,7 +1178,7 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) uint32_t endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); // if it's a full block, just read directly from disk unless it's the cached hunk - chd_error err = CHDERR_NONE; + std::error_condition err; if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) err = read_hunk(curhunk, dest); @@ -1158,7 +1188,7 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) if (curhunk != m_cachehunk) { err = read_hunk(curhunk, &m_cache[0]); - if (err != CHDERR_NONE) + if (err) return err; m_cachehunk = curhunk; } @@ -1166,15 +1196,15 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) } // handle errors and advance - if (err != CHDERR_NONE) + if (err) return err; dest += endoffs + 1 - startoffs; } - return CHDERR_NONE; + return std::error_condition(); } /** - * @fn chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes) + * @fn std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes) * * @brief ------------------------------------------------- * write_bytes - write to the CHD at a byte level, using the cache to handle partial @@ -1185,10 +1215,10 @@ chd_error chd_file::read_bytes(uint64_t offset, void *buffer, uint32_t bytes) * @param buffer The buffer. * @param bytes The bytes. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes) +std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t bytes) { // iterate over hunks uint32_t first_hunk = offset / m_hunkbytes; @@ -1201,7 +1231,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by uint32_t endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); // if it's a full block, just write directly to disk unless it's the cached hunk - chd_error err = CHDERR_NONE; + std::error_condition err; if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) err = write_hunk(curhunk, source); @@ -1211,7 +1241,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by if (curhunk != m_cachehunk) { err = read_hunk(curhunk, &m_cache[0]); - if (err != CHDERR_NONE) + if (err) return err; m_cachehunk = curhunk; } @@ -1220,15 +1250,15 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by } // handle errors and advance - if (err != CHDERR_NONE) + if (err) return err; source += endoffs + 1 - startoffs; } - return CHDERR_NONE; + return std::error_condition(); } /** - * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output) + * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output) * * @brief ------------------------------------------------- * read_metadata - read the indexed metadata of the given type @@ -1244,7 +1274,7 @@ chd_error chd_file::write_bytes(uint64_t offset, const void *buffer, uint32_t by * @return The metadata. */ -chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output) +std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output) { // wrap this for clean reporting try @@ -1252,23 +1282,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind // if we didn't find it, just return metadata_entry metaentry; if (!metadata_find(searchtag, searchindex, metaentry)) - throw CHDERR_METADATA_NOT_FOUND; + throw std::error_condition(error::METADATA_NOT_FOUND); // read the metadata output.assign(metaentry.length, '\0'); file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); - return CHDERR_NONE; + return std::error_condition(); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output) + * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output) * * @brief Reads a metadata. * @@ -1282,7 +1311,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind * @return The metadata. */ -chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output) +std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output) { // wrap this for clean reporting try @@ -1290,23 +1319,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind // if we didn't find it, just return metadata_entry metaentry; if (!metadata_find(searchtag, searchindex, metaentry)) - throw CHDERR_METADATA_NOT_FOUND; + throw std::error_condition(error::METADATA_NOT_FOUND); // read the metadata output.resize(metaentry.length); file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); - return CHDERR_NONE; + return std::error_condition(); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen) + * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen) * * @brief Reads a metadata. * @@ -1322,7 +1350,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind * @return The metadata. */ -chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen) +std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen) { // wrap this for clean reporting try @@ -1330,23 +1358,22 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind // if we didn't find it, just return metadata_entry metaentry; if (!metadata_find(searchtag, searchindex, metaentry)) - throw CHDERR_METADATA_NOT_FOUND; + throw std::error_condition(error::METADATA_NOT_FOUND); // read the metadata resultlen = metaentry.length; file_read(metaentry.offset + METADATA_HEADER_SIZE, output, std::min(outputlen, resultlen)); - return CHDERR_NONE; + return std::error_condition(); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags) + * @fn std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags) * * @brief Reads a metadata. * @@ -1362,7 +1389,7 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind * @return The metadata. */ -chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags) +std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags) { // wrap this for clean reporting try @@ -1370,25 +1397,24 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind // if we didn't find it, just return metadata_entry metaentry; if (!metadata_find(searchtag, searchindex, metaentry)) - throw CHDERR_METADATA_NOT_FOUND; + throw std::error_condition(error::METADATA_NOT_FOUND); // read the metadata output.resize(metaentry.length); file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); resulttag = metaentry.metatag; resultflags = metaentry.flags; - return CHDERR_NONE; + return std::error_condition(); } - - // just return errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // just return errors return err; } } /** - * @fn chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags) + * @fn std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags) * * @brief ------------------------------------------------- * write_metadata - write the indexed metadata of the given type @@ -1400,17 +1426,17 @@ chd_error chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchind * @param inputlen The inputlen. * @param flags The flags. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags) +std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags) { // wrap this for clean reporting try { // must write at least 1 byte and no more than 16MB if (inputlen < 1 || inputlen >= 16 * 1024 * 1024) - return CHDERR_INVALID_PARAMETER; + return std::error_condition(std::errc::invalid_argument); // find the entry if it already exists metadata_entry metaentry; @@ -1459,18 +1485,17 @@ chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, // update the hash metadata_update_hash(); - return CHDERR_NONE; + return std::error_condition(); } - - // return any errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // return any errors return err; } } /** - * @fn chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex) + * @fn std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex) * * @brief ------------------------------------------------- * delete_metadata - remove the given metadata from the list @@ -1482,10 +1507,10 @@ chd_error chd_file::write_metadata(chd_metadata_tag metatag, uint32_t metaindex, * @param metatag The metatag. * @param metaindex The metaindex. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex) +std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex) { // wrap this for clean reporting try @@ -1493,22 +1518,21 @@ chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex // find the entry metadata_entry metaentry; if (!metadata_find(metatag, metaindex, metaentry)) - throw CHDERR_METADATA_NOT_FOUND; + throw std::error_condition(error::METADATA_NOT_FOUND); // point the previous to the next, unlinking us metadata_set_previous_next(metaentry.prev, metaentry.next); - return CHDERR_NONE; + return std::error_condition(); } - - // return any errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // return any errors return err; } } /** - * @fn chd_error chd_file::clone_all_metadata(chd_file &source) + * @fn std::error_condition chd_file::clone_all_metadata(chd_file &source) * * @brief ------------------------------------------------- * clone_all_metadata - clone the metadata from one CHD to a second @@ -1518,10 +1542,10 @@ chd_error chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex * * @param [in,out] source Another instance to copy. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::clone_all_metadata(chd_file &source) +std::error_condition chd_file::clone_all_metadata(chd_file &source) { // wrap this for clean reporting try @@ -1540,16 +1564,15 @@ chd_error chd_file::clone_all_metadata(chd_file &source) source.file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length); // write it to the destination - chd_error err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags); - if (err != CHDERR_NONE) + std::error_condition err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags); + if (err) throw err; } - return CHDERR_NONE; + return std::error_condition(); } - - // return any errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // return any errors return err; } } @@ -1607,7 +1630,7 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1) } /** - * @fn chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *config) + * @fn std::error_condition chd_file::codec_configure(chd_codec_type codec, int param, void *config) * * @brief ------------------------------------------------- * codec_config - set internal codec parameters @@ -1617,10 +1640,10 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1) * @param param The parameter. * @param [in,out] config If non-null, the configuration. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *config) +std::error_condition chd_file::codec_configure(chd_codec_type codec, int param, void *config) { // wrap this for clean reporting try @@ -1630,14 +1653,13 @@ chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *confi if (m_compression[codecnum] == codec) { m_decompressor[codecnum]->configure(param, config); - return CHDERR_NONE; + return std::error_condition(); } - return CHDERR_INVALID_PARAMETER; + return std::errc::invalid_argument; } - - // return any errors - catch (chd_error &err) + catch (std::error_condition const &err) { + // return any errors return err; } } @@ -1654,44 +1676,49 @@ chd_error chd_file::codec_configure(chd_codec_type codec, int param, void *confi * @return null if it fails, else a char*. */ -const char *chd_file::error_string(chd_error err) +std::error_category const &chd_category() noexcept { - switch (err) + class chd_category_impl : public std::error_category { - case CHDERR_NONE: return "no error"; - case CHDERR_NO_INTERFACE: return "no drive interface"; - case CHDERR_OUT_OF_MEMORY: return "out of memory"; - case CHDERR_NOT_OPEN: return "file not open"; - case CHDERR_ALREADY_OPEN: return "file already open"; - case CHDERR_INVALID_FILE: return "invalid file"; - case CHDERR_INVALID_PARAMETER: return "invalid parameter"; - case CHDERR_INVALID_DATA: return "invalid data"; - case CHDERR_FILE_NOT_FOUND: return "file not found"; - case CHDERR_REQUIRES_PARENT: return "requires parent"; - case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable"; - case CHDERR_READ_ERROR: return "read error"; - case CHDERR_WRITE_ERROR: return "write error"; - case CHDERR_CODEC_ERROR: return "codec error"; - case CHDERR_INVALID_PARENT: return "invalid parent"; - case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range"; - case CHDERR_DECOMPRESSION_ERROR: return "decompression error"; - case CHDERR_COMPRESSION_ERROR: return "compression error"; - case CHDERR_CANT_CREATE_FILE: return "can't create file"; - case CHDERR_CANT_VERIFY: return "can't verify file"; - case CHDERR_NOT_SUPPORTED: return "operation not supported"; - case CHDERR_METADATA_NOT_FOUND: return "can't find metadata"; - case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size"; - case CHDERR_UNSUPPORTED_VERSION: return "mismatched DIFF and CHD or unsupported CHD version"; - case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify"; - case CHDERR_INVALID_METADATA: return "invalid metadata"; - case CHDERR_INVALID_STATE: return "invalid state"; - case CHDERR_OPERATION_PENDING: return "operation pending"; - case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format"; - case CHDERR_UNKNOWN_COMPRESSION: return "unknown compression type"; - case CHDERR_WALKING_PARENT: return "currently examining parent"; - case CHDERR_COMPRESSING: return "currently compressing"; - default: return "undocumented error"; - } + virtual char const *name() const noexcept override { return "chd"; } + + virtual std::string message(int condition) const override + { + using namespace std::literals; + static std::string_view const s_messages[] = { + "No error"sv, + "No drive interface"sv, + "File not open"sv, + "File already open"sv, + "Invalid file"sv, + "Invalid data"sv, + "Requires parent"sv, + "File not writeable"sv, + "Codec error"sv, + "Invalid parent"sv, + "Hunk out of range"sv, + "Decompression error"sv, + "Compression error"sv, + "Can't verify file"sv, + "Can't find metadata"sv, + "Invalid metadata size"sv, + "Mismatched DIFF and CHD or unsupported CHD version"sv, + "Incomplete verify"sv, + "Invalid metadata"sv, + "Invalid state"sv, + "Operation pending"sv, + "Unsupported format"sv, + "Unknown compression type"sv, + "Currently examining parent"sv, + "Currently compressing"sv }; + if ((0 <= condition) && (std::size(s_messages) > condition)) + return std::string(s_messages[condition]); + else + return "Unknown error"s; + } + }; + static chd_category_impl const s_chd_category_instance; + return s_chd_category_instance; } @@ -1716,15 +1743,15 @@ uint32_t chd_file::guess_unitbytes() // look for hard disk metadata; if found, then the unit size == sector size std::string metadata; int i0, i1, i2, i3; - if (read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) == CHDERR_NONE && sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4) + if (!read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) && sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4) return i3; // look for CD-ROM metadata; if found, then the unit size == CD frame size - if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || - read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || - read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE || - read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || - read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE) + if (!read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) || + !read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) || + !read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) || + !read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) || + !read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata)) return CD_FRAME_SIZE; // otherwise, just map 1:1 with the hunk size @@ -1751,7 +1778,7 @@ void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V3_HEADER_SIZE) - throw CHDERR_INVALID_FILE; + throw std::error_condition(error::INVALID_FILE); // extract core info m_logicalbytes = be_read(&rawheader[28], 8); @@ -1771,7 +1798,7 @@ void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1) case 1: m_compression[0] = CHD_CODEC_ZLIB; break; case 2: m_compression[0] = CHD_CODEC_ZLIB; break; case 3: m_compression[0] = CHD_CODEC_AVHUFF; break; - default: throw CHDERR_UNKNOWN_COMPRESSION; + default: throw std::error_condition(error::UNKNOWN_COMPRESSION); } m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE; @@ -1814,7 +1841,7 @@ void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V4_HEADER_SIZE) - throw CHDERR_INVALID_FILE; + throw std::error_condition(error::INVALID_FILE); // extract core info m_logicalbytes = be_read(&rawheader[28], 8); @@ -1834,7 +1861,7 @@ void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1) case 1: m_compression[0] = CHD_CODEC_ZLIB; break; case 2: m_compression[0] = CHD_CODEC_ZLIB; break; case 3: m_compression[0] = CHD_CODEC_AVHUFF; break; - default: throw CHDERR_UNKNOWN_COMPRESSION; + default: throw std::error_condition(error::UNKNOWN_COMPRESSION); } m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE; @@ -1874,7 +1901,7 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V5_HEADER_SIZE) - throw CHDERR_INVALID_FILE; + throw std::error_condition(error::INVALID_FILE); // extract core info m_logicalbytes = be_read(&rawheader[32], 8); @@ -1908,7 +1935,7 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1) } /** - * @fn chd_error chd_file::compress_v5_map() + * @fn std::error_condition chd_file::compress_v5_map() * * @brief ------------------------------------------------- * compress_v5_map - compress the v5 map and write it to the end of the file @@ -1917,10 +1944,10 @@ void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1) * @exception CHDERR_COMPRESSION_ERROR Thrown when a chderr compression error error * condition occurs. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::compress_v5_map() +std::error_condition chd_file::compress_v5_map() { try { @@ -2015,10 +2042,10 @@ chd_error chd_file::compress_v5_map() bitstream_out bitbuf(&compressed[16], compressed.size() - 16); huffman_error err = encoder.compute_tree_from_histo(); if (err != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(error::COMPRESSION_ERROR); err = encoder.export_tree_rle(bitbuf); if (err != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(error::COMPRESSION_ERROR); // encode the data for (uint8_t *src = &compression_rle[0]; src < dest; src++) @@ -2113,9 +2140,9 @@ chd_error chd_file::compress_v5_map() uint8_t rawbuf[sizeof(uint64_t)]; be_write(rawbuf, m_mapoffset, 8); file_write(m_mapoffset_offset, rawbuf, sizeof(rawbuf)); - return CHDERR_NONE; + return std::error_condition(); } - catch (chd_error &err) + catch (std::error_condition const &err) { return err; } @@ -2160,7 +2187,7 @@ void chd_file::decompress_v5_map() huffman_decoder<16, 8> decoder; huffman_error err = decoder.import_tree_rle(bitbuf); if (err != HUFFERR_NONE) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(error::DECOMPRESSION_ERROR); uint8_t lastcomp = 0; int repcount = 0; for (int hunknum = 0; hunknum < m_hunkcount; hunknum++) @@ -2244,11 +2271,11 @@ void chd_file::decompress_v5_map() // verify the final CRC if (util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(error::DECOMPRESSION_ERROR); } /** - * @fn chd_error chd_file::create_common() + * @fn std::error_condition chd_file::create_common() * * @brief ------------------------------------------------- * create_common - command path when creating a new CHD file @@ -2264,7 +2291,7 @@ void chd_file::decompress_v5_map() * @return The new common. */ -chd_error chd_file::create_common() +std::error_condition chd_file::create_common() { // wrap in try for proper error handling try @@ -2273,14 +2300,14 @@ chd_error chd_file::create_common() m_metaoffset = 0; // if we have a parent, it must be V3 or later - if (m_parent != nullptr && m_parent->version() < 3) - throw CHDERR_UNSUPPORTED_VERSION; + if (m_parent && m_parent->version() < 3) + throw std::error_condition(error::UNSUPPORTED_VERSION); // must be an even number of units per hunk if (m_hunkbytes % m_unitbytes != 0) - throw CHDERR_INVALID_PARAMETER; - if (m_parent != nullptr && m_unitbytes != m_parent->unit_bytes()) - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); + if (m_parent && m_unitbytes != m_parent->unit_bytes()) + throw std::error_condition(std::errc::invalid_argument); // verify the compression types bool found_zero = false; @@ -2290,9 +2317,9 @@ chd_error chd_file::create_common() if (elem == CHD_CODEC_NONE) found_zero = true; else if (found_zero) - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); else if (!chd_codec_list::codec_exists(elem)) - throw CHDERR_UNKNOWN_COMPRESSION; + throw std::error_condition(error::UNKNOWN_COMPRESSION); } // create our V5 header @@ -2342,10 +2369,9 @@ chd_error chd_file::create_common() // finish opening the file create_open_common(); } - - // handle errors by closing ourself - catch (chd_error &err) + catch (std::error_condition const &err) { + // handle errors by closing ourself close(); return err; } @@ -2354,11 +2380,11 @@ chd_error chd_file::create_common() close(); throw; } - return CHDERR_NONE; + return std::error_condition(); } /** - * @fn chd_error chd_file::open_common(bool writeable) + * @fn std::error_condition chd_file::open_common(bool writeable) * * @brief ------------------------------------------------- * open_common - common path when opening an existing CHD file for input @@ -2377,10 +2403,10 @@ chd_error chd_file::create_common() * * @param writeable true if writeable. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file::open_common(bool writeable) +std::error_condition chd_file::open_common(bool writeable) { // wrap in try for proper error handling try @@ -2394,7 +2420,7 @@ chd_error chd_file::open_common(bool writeable) // verify the signature if (memcmp(rawheader, "MComprHD", 8) != 0) - throw CHDERR_INVALID_FILE; + throw std::error_condition(error::INVALID_FILE); m_version = be_read(&rawheader[12], 4); @@ -2405,7 +2431,7 @@ chd_error chd_file::open_common(bool writeable) case 3: parse_v3_header(rawheader, parentsha1); break; case 4: parse_v4_header(rawheader, parentsha1); break; case 5: parse_v5_header(rawheader, parentsha1); break; - default: throw CHDERR_UNSUPPORTED_VERSION; + default: throw std::error_condition(error::UNSUPPORTED_VERSION); } // only allow writes to the most recent version @@ -2413,27 +2439,26 @@ chd_error chd_file::open_common(bool writeable) m_allow_writes = false; if (writeable && !m_allow_writes) - throw CHDERR_FILE_NOT_WRITEABLE; + throw std::error_condition(error::FILE_NOT_WRITEABLE); // make sure we have a parent if we need one (and don't if we don't) if (parentsha1 != util::sha1_t::null) { - if (m_parent == nullptr) + if (!m_parent) m_parent_missing = true; else if (m_parent->sha1() != parentsha1) - throw CHDERR_INVALID_PARENT; + throw std::error_condition(error::INVALID_PARENT); } - else if (m_parent != nullptr) - throw CHDERR_INVALID_PARAMETER; + else if (m_parent) + throw std::error_condition(std::errc::invalid_argument); // finish opening the file create_open_common(); - return CHDERR_NONE; + return std::error_condition(); } - - // handle errors by closing ourself - catch (chd_error &err) + catch (std::error_condition const &err) { + // handle errors by closing ourself close(); return err; } @@ -2457,7 +2482,7 @@ void chd_file::create_open_common() { m_decompressor[decompnum] = chd_codec_list::new_decompressor(m_compression[decompnum], *this); if (m_decompressor[decompnum] == nullptr && m_compression[decompnum] != 0) - throw CHDERR_UNKNOWN_COMPRESSION; + throw std::error_condition(error::UNKNOWN_COMPRESSION); } // read the map; v5+ compressed drives need to read and decompress their map @@ -2494,30 +2519,30 @@ void chd_file::create_open_common() void chd_file::verify_proper_compression_append(uint32_t hunknum) { // punt if no file - if (m_file == nullptr) - throw CHDERR_NOT_OPEN; + if (!m_file) + throw std::error_condition(error::NOT_OPEN); // return an error if out of range if (hunknum >= m_hunkcount) - throw CHDERR_HUNK_OUT_OF_RANGE; + throw std::error_condition(error::HUNK_OUT_OF_RANGE); // if not writeable, fail if (!m_allow_writes) - throw CHDERR_FILE_NOT_WRITEABLE; + throw std::error_condition(error::FILE_NOT_WRITEABLE); // compressed writes only via this interface if (!compressed()) - throw CHDERR_FILE_NOT_WRITEABLE; + throw std::error_condition(error::FILE_NOT_WRITEABLE); // only permitted to write new blocks uint8_t *rawmap = &m_rawmap[hunknum * 12]; if (rawmap[0] != 0xff) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(error::COMPRESSION_ERROR); // if this isn't the first block, only permitted to write immediately // after the previous one if (hunknum != 0 && rawmap[-12] == 0xff) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(error::COMPRESSION_ERROR); } /** @@ -2572,7 +2597,7 @@ void chd_file::hunk_copy_from_self(uint32_t hunknum, uint32_t otherhunk) // only permitted to reference prior hunks if (otherhunk >= hunknum) - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); // update the map entry uint8_t *rawmap = &m_rawmap[hunknum * 12]; @@ -2841,7 +2866,7 @@ void chd_file_compressor::compress_begin() } /** - * @fn chd_error chd_file_compressor::compress_continue(double &progress, double &ratio) + * @fn std::error_condition chd_file_compressor::compress_continue(double &progress, double &ratio) * * @brief ------------------------------------------------- * compress_continue - continue compression @@ -2850,14 +2875,14 @@ void chd_file_compressor::compress_begin() * @param [in,out] progress The progress. * @param [in,out] ratio The ratio. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chd_file_compressor::compress_continue(double &progress, double &ratio) +std::error_condition chd_file_compressor::compress_continue(double &progress, double &ratio) { // if we got an error, return an error if (m_read_error) - return CHDERR_READ_ERROR; + return std::errc::io_error; // if done reading, queue some more while (m_read_queue_offset < m_logicalbytes && osd_work_queue_items(m_read_queue) < 2) @@ -2911,8 +2936,8 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio // if we're uncompressed, use regular writes else if (!compressed()) { - chd_error err = write_hunk(item.m_hunknum, item.m_data); - if (err != CHDERR_NONE) + std::error_condition err = write_hunk(item.m_hunknum, item.m_data); + if (err) return err; // writes of all-0 data don't actually take space, so see if we count this @@ -2973,7 +2998,7 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio { osd_work_queue_wait(m_read_queue, 30 * osd_ticks_per_second()); if (!compressed()) - return CHDERR_NONE; + return std::error_condition(); set_raw_sha1(m_compsha1.finish()); return compress_v5_map(); } @@ -2994,7 +3019,7 @@ chd_error chd_file_compressor::compress_continue(double &progress, double &ratio m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd != nullptr) osd_work_item_wait(m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd, osd_ticks_per_second()); - return m_walking_parent ? CHDERR_WALKING_PARENT : CHDERR_COMPRESSING; + return m_walking_parent ? error::WALKING_PARENT : error::COMPRESSING; } /** @@ -3171,12 +3196,12 @@ void chd_file_compressor::async_read() // advance the read pointer m_read_done_offset += numbytes; } - catch (chd_error& err) + catch (std::error_condition const &err) { - fprintf(stderr, "CHD error occurred: %s\n", chd_file::error_string(err)); + fprintf(stderr, "CHD error occurred: %s\n", err.message().c_str()); m_read_error = true; } - catch (std::exception& ex) + catch (std::exception const &ex) { fprintf(stderr, "exception occurred: %s\n", ex.what()); m_read_error = true; diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index 705967d3dda..8d3e639438b 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -7,18 +7,22 @@ MAME Compressed Hunks of Data file format ***************************************************************************/ - -#ifndef MAME_UTIL_CHD_H -#define MAME_UTIL_CHD_H +#ifndef MAME_LIB_UTIL_CHD_H +#define MAME_LIB_UTIL_CHD_H #pragma once -#include "osdcore.h" -#include <string> -#include "corefile.h" -#include "hashing.h" #include "chdcodec.h" +#include "hashing.h" +#include "ioprocs.h" + +#include "osdcore.h" + #include <atomic> +#include <string> +#include <string_view> +#include <system_error> + /*************************************************************************** @@ -190,86 +194,49 @@ //************************************************************************** // pseudo-codecs returned by hunk_info -const chd_codec_type CHD_CODEC_SELF = 1; // copy of another hunk -const chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk -const chd_codec_type CHD_CODEC_MINI = 3; // legacy "mini" 8-byte repeat +constexpr chd_codec_type CHD_CODEC_SELF = 1; // copy of another hunk +constexpr chd_codec_type CHD_CODEC_PARENT = 2; // copy of a parent's hunk +constexpr chd_codec_type CHD_CODEC_MINI = 3; // legacy "mini" 8-byte repeat // core types typedef uint32_t chd_metadata_tag; // metadata parameters -const chd_metadata_tag CHDMETATAG_WILDCARD = 0; -const uint32_t CHDMETAINDEX_APPEND = ~0; +constexpr chd_metadata_tag CHDMETATAG_WILDCARD = 0; +constexpr uint32_t CHDMETAINDEX_APPEND = ~0; // metadata flags -const uint8_t CHD_MDFLAGS_CHECKSUM = 0x01; // indicates data is checksummed +constexpr uint8_t CHD_MDFLAGS_CHECKSUM = 0x01; // indicates data is checksummed // standard hard disk metadata -const chd_metadata_tag HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D'); +constexpr chd_metadata_tag HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D'); extern const char *HARD_DISK_METADATA_FORMAT; // hard disk identify information -const chd_metadata_tag HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T'); +constexpr chd_metadata_tag HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T'); // hard disk key information -const chd_metadata_tag HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' '); +constexpr chd_metadata_tag HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' '); // pcmcia CIS information -const chd_metadata_tag PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' '); +constexpr chd_metadata_tag PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' '); // standard CD-ROM metadata -const chd_metadata_tag CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D'); -const chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R'); +constexpr chd_metadata_tag CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D'); +constexpr chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R'); extern const char *CDROM_TRACK_METADATA_FORMAT; -const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2'); +constexpr chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2'); extern const char *CDROM_TRACK_METADATA2_FORMAT; -const chd_metadata_tag GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T'); -const chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C', 'H', 'G', 'D'); +constexpr chd_metadata_tag GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T'); +constexpr chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C', 'H', 'G', 'D'); extern const char *GDROM_TRACK_METADATA_FORMAT; // standard A/V metadata -const chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V'); +constexpr chd_metadata_tag AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V'); extern const char *AV_METADATA_FORMAT; // A/V laserdisc frame metadata -const chd_metadata_tag AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D'); - -// error types -enum chd_error -{ - CHDERR_NONE, - CHDERR_NO_INTERFACE, - CHDERR_OUT_OF_MEMORY, - CHDERR_NOT_OPEN, - CHDERR_ALREADY_OPEN, - CHDERR_INVALID_FILE, - CHDERR_INVALID_PARAMETER, - CHDERR_INVALID_DATA, - CHDERR_FILE_NOT_FOUND, - CHDERR_REQUIRES_PARENT, - CHDERR_FILE_NOT_WRITEABLE, - CHDERR_READ_ERROR, - CHDERR_WRITE_ERROR, - CHDERR_CODEC_ERROR, - CHDERR_INVALID_PARENT, - CHDERR_HUNK_OUT_OF_RANGE, - CHDERR_DECOMPRESSION_ERROR, - CHDERR_COMPRESSION_ERROR, - CHDERR_CANT_CREATE_FILE, - CHDERR_CANT_VERIFY, - CHDERR_NOT_SUPPORTED, - CHDERR_METADATA_NOT_FOUND, - CHDERR_INVALID_METADATA_SIZE, - CHDERR_UNSUPPORTED_VERSION, - CHDERR_VERIFY_INCOMPLETE, - CHDERR_INVALID_METADATA, - CHDERR_INVALID_STATE, - CHDERR_OPERATION_PENDING, - CHDERR_UNSUPPORTED_FORMAT, - CHDERR_UNKNOWN_COMPRESSION, - CHDERR_WALKING_PARENT, - CHDERR_COMPRESSING -}; +constexpr chd_metadata_tag AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D'); @@ -277,9 +244,6 @@ enum chd_error // TYPE DEFINITIONS //************************************************************************** -class chd_codec; - - // ======================> chd_file // core file class @@ -289,22 +253,49 @@ class chd_file friend class chd_verifier; // constants - static const uint32_t HEADER_VERSION = 5; - static const uint32_t V3_HEADER_SIZE = 120; - static const uint32_t V4_HEADER_SIZE = 108; - static const uint32_t V5_HEADER_SIZE = 124; - static const uint32_t MAX_HEADER_SIZE = V5_HEADER_SIZE; + static constexpr uint32_t HEADER_VERSION = 5; + static constexpr uint32_t V3_HEADER_SIZE = 120; + static constexpr uint32_t V4_HEADER_SIZE = 108; + static constexpr uint32_t V5_HEADER_SIZE = 124; + static constexpr uint32_t MAX_HEADER_SIZE = V5_HEADER_SIZE; public: + // error types + enum class error + { + NO_INTERFACE = 1, + NOT_OPEN, + ALREADY_OPEN, + INVALID_FILE, + INVALID_DATA, + REQUIRES_PARENT, + FILE_NOT_WRITEABLE, + CODEC_ERROR, + INVALID_PARENT, + HUNK_OUT_OF_RANGE, + DECOMPRESSION_ERROR, + COMPRESSION_ERROR, + CANT_VERIFY, + METADATA_NOT_FOUND, + INVALID_METADATA_SIZE, + UNSUPPORTED_VERSION, + VERIFY_INCOMPLETE, + INVALID_METADATA, + INVALID_STATE, + OPERATION_PENDING, + UNSUPPORTED_FORMAT, + UNKNOWN_COMPRESSION, + WALKING_PARENT, + COMPRESSING + }; + // construction/destruction chd_file(); virtual ~chd_file(); - // operators - operator util::core_file &() { return *m_file; } - // getters - bool opened() const { return (m_file != nullptr); } + util::random_read &file(); + bool opened() const { return bool(m_file); } uint32_t version() const { return m_version; } uint64_t logical_bytes() const { return m_logicalbytes; } uint32_t hunk_bytes() const { return m_hunkbytes; } @@ -317,52 +308,49 @@ public: util::sha1_t sha1(); util::sha1_t raw_sha1(); util::sha1_t parent_sha1(); - chd_error hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes); + std::error_condition hunk_info(uint32_t hunknum, chd_codec_type &compressor, uint32_t &compbytes); // setters void set_raw_sha1(util::sha1_t rawdata); void set_parent_sha1(util::sha1_t parent); // file create - chd_error create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]); - chd_error create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]); - chd_error create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent); - chd_error create(util::core_file &file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent); + std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]); + std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4]); + std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent); + std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent); // file open - chd_error open(const char *filename, bool writeable = false, chd_file *parent = nullptr); - chd_error open(util::core_file &file, bool writeable = false, chd_file *parent = nullptr); + std::error_condition open(std::string_view filename, bool writeable = false, chd_file *parent = nullptr); + std::error_condition open(util::random_read_write::ptr &&file, bool writeable = false, chd_file *parent = nullptr); // file close void close(); // read/write - chd_error read_hunk(uint32_t hunknum, void *buffer); - chd_error write_hunk(uint32_t hunknum, const void *buffer); - chd_error read_units(uint64_t unitnum, void *buffer, uint32_t count = 1); - chd_error write_units(uint64_t unitnum, const void *buffer, uint32_t count = 1); - chd_error read_bytes(uint64_t offset, void *buffer, uint32_t bytes); - chd_error write_bytes(uint64_t offset, const void *buffer, uint32_t bytes); + std::error_condition read_hunk(uint32_t hunknum, void *buffer); + std::error_condition write_hunk(uint32_t hunknum, const void *buffer); + std::error_condition read_units(uint64_t unitnum, void *buffer, uint32_t count = 1); + std::error_condition write_units(uint64_t unitnum, const void *buffer, uint32_t count = 1); + std::error_condition read_bytes(uint64_t offset, void *buffer, uint32_t bytes); + std::error_condition write_bytes(uint64_t offset, const void *buffer, uint32_t bytes); // metadata management - chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output); - chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output); - chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen); - chd_error read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags); - chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags = CHD_MDFLAGS_CHECKSUM); - chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::string &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input.c_str(), input.length() + 1, flags); } - chd_error write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::vector<uint8_t> &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, &input[0], input.size(), flags); } - chd_error delete_metadata(chd_metadata_tag metatag, uint32_t metaindex); - chd_error clone_all_metadata(chd_file &source); + std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output); + std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output); + std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t &resultlen); + std::error_condition read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::vector<uint8_t> &output, chd_metadata_tag &resulttag, uint8_t &resultflags); + std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const void *inputbuf, uint32_t inputlen, uint8_t flags = CHD_MDFLAGS_CHECKSUM); + std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::string &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, input.c_str(), input.length() + 1, flags); } + std::error_condition write_metadata(chd_metadata_tag metatag, uint32_t metaindex, const std::vector<uint8_t> &input, uint8_t flags = CHD_MDFLAGS_CHECKSUM) { return write_metadata(metatag, metaindex, &input[0], input.size(), flags); } + std::error_condition delete_metadata(chd_metadata_tag metatag, uint32_t metaindex); + std::error_condition clone_all_metadata(chd_file &source); // hashing helper util::sha1_t compute_overall_sha1(util::sha1_t rawsha1); // codec interfaces - chd_error codec_configure(chd_codec_type codec, int param, void *config); - - // static helpers - static const char *error_string(chd_error err); + std::error_condition codec_configure(chd_codec_type codec, int param, void *config); private: struct metadata_entry; @@ -383,10 +371,10 @@ private: void parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1); void parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1); void parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1); - chd_error compress_v5_map(); + std::error_condition compress_v5_map(); void decompress_v5_map(); - chd_error create_common(); - chd_error open_common(bool writeable); + std::error_condition create_common(); + std::error_condition open_common(bool writeable); void create_open_common(); void verify_proper_compression_append(uint32_t hunknum); void hunk_write_compressed(uint32_t hunknum, int8_t compression, const uint8_t *compressed, uint32_t complength, util::crc16_t crc16); @@ -398,42 +386,41 @@ private: static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2); // file characteristics - util::core_file * m_file; // handle to the open core file - bool m_owns_file; // flag indicating if this file should be closed on chd_close() + util::random_read_write::ptr m_file; // handle to the open core file bool m_allow_reads; // permit reads from this CHD? bool m_allow_writes; // permit writes to this CHD? // core parameters from the header - uint32_t m_version; // version of the header - uint64_t m_logicalbytes; // logical size of the raw CHD data in bytes - uint64_t m_mapoffset; // offset of map - uint64_t m_metaoffset; // offset to first metadata bit - uint32_t m_hunkbytes; // size of each raw hunk in bytes - uint32_t m_hunkcount; // number of hunks represented - uint32_t m_unitbytes; // size of each unit in bytes - uint64_t m_unitcount; // number of units represented + uint32_t m_version; // version of the header + uint64_t m_logicalbytes; // logical size of the raw CHD data in bytes + uint64_t m_mapoffset; // offset of map + uint64_t m_metaoffset; // offset to first metadata bit + uint32_t m_hunkbytes; // size of each raw hunk in bytes + uint32_t m_hunkcount; // number of hunks represented + uint32_t m_unitbytes; // size of each unit in bytes + uint64_t m_unitcount; // number of units represented chd_codec_type m_compression[4]; // array of compression types used chd_file * m_parent; // pointer to parent file, or nullptr if none bool m_parent_missing; // are we missing our parent? // key offsets within the header - uint64_t m_mapoffset_offset; // offset of map offset field - uint64_t m_metaoffset_offset;// offset of metaoffset field - uint64_t m_sha1_offset; // offset of SHA1 field - uint64_t m_rawsha1_offset; // offset of raw SHA1 field - uint64_t m_parentsha1_offset;// offset of paren SHA1 field + uint64_t m_mapoffset_offset; // offset of map offset field + uint64_t m_metaoffset_offset;// offset of metaoffset field + uint64_t m_sha1_offset; // offset of SHA1 field + uint64_t m_rawsha1_offset; // offset of raw SHA1 field + uint64_t m_parentsha1_offset;// offset of paren SHA1 field // map information - uint32_t m_mapentrybytes; // length of each entry in a map - std::vector<uint8_t> m_rawmap; // raw map data + uint32_t m_mapentrybytes; // length of each entry in a map + std::vector<uint8_t> m_rawmap; // raw map data // compression management - chd_decompressor * m_decompressor[4]; // array of decompression codecs - std::vector<uint8_t> m_compressed; // temporary buffer for compressed data + chd_decompressor::ptr m_decompressor[4]; // array of decompression codecs + std::vector<uint8_t> m_compressed; // temporary buffer for compressed data // caching - std::vector<uint8_t> m_cache; // single-hunk cache for partial reads/writes - uint32_t m_cachehunk; // which hunk is in the cache? + std::vector<uint8_t> m_cache; // single-hunk cache for partial reads/writes + uint32_t m_cachehunk; // which hunk is in the cache? }; @@ -449,7 +436,7 @@ public: // compression management void compress_begin(); - chd_error compress_continue(double &progress, double &ratio); + std::error_condition compress_continue(double &progress, double &ratio); protected: // required override: read more data @@ -470,24 +457,24 @@ private: void add(uint64_t itemnum, util::crc16_t crc16, util::sha1_t sha1); // constants - static const uint64_t NOT_FOUND = ~uint64_t(0); + static constexpr uint64_t NOT_FOUND = ~uint64_t(0); + private: // internal entry struct entry_t { entry_t * m_next; // next entry in list - uint64_t m_itemnum; // item number + uint64_t m_itemnum; // item number util::sha1_t m_sha1; // SHA-1 of the block }; // block of entries struct entry_block { - entry_block(entry_block *prev) - : m_next(prev), m_nextalloc(0) { } + entry_block(entry_block *prev) : m_next(prev), m_nextalloc(0) { } entry_block * m_next; // next block in list - uint32_t m_nextalloc; // next to be allocated + uint32_t m_nextalloc; // next to be allocated entry_t m_array[16384]; // array of entries }; @@ -551,8 +538,8 @@ private: // current compression status bool m_walking_parent; // are we building the parent map? - uint64_t m_total_in; // total bytes in - uint64_t m_total_out; // total bytes out + uint64_t m_total_in; // total bytes in + uint64_t m_total_out; // total bytes out util::sha1_creator m_compsha1; // running SHA-1 on raw data // hash lookup maps @@ -561,20 +548,31 @@ private: // read I/O thread osd_work_queue * m_read_queue; // work queue for reading - uint64_t m_read_queue_offset;// next offset to enqueue - uint64_t m_read_done_offset; // next offset that will complete + uint64_t m_read_queue_offset;// next offset to enqueue + uint64_t m_read_done_offset; // next offset that will complete bool m_read_error; // error during reading? // work item thread - static const int WORK_BUFFER_HUNKS = 256; + static constexpr int WORK_BUFFER_HUNKS = 256; osd_work_queue * m_work_queue; // queue for doing work on other threads - std::vector<uint8_t> m_work_buffer; // buffer containing hunk data to work on - std::vector<uint8_t> m_compressed_buffer;// buffer containing compressed data + std::vector<uint8_t> m_work_buffer; // buffer containing hunk data to work on + std::vector<uint8_t> m_compressed_buffer;// buffer containing compressed data work_item m_work_item[WORK_BUFFER_HUNKS]; // status of each hunk chd_compressor_group * m_codecs[WORK_MAX_THREADS]; // codecs to use // output state - uint32_t m_write_hunk; // next hunk to write + uint32_t m_write_hunk; // next hunk to write }; -#endif // MAME_UTIL_CHD_H + +// error category for CHD errors +std::error_category const &chd_category() noexcept; +inline std::error_condition make_error_condition(chd_file::error err) noexcept { return std::error_condition(int(err), chd_category()); } + +namespace std { + +template <> struct is_error_condition_enum<chd_file::error> : public std::true_type { }; + +} // namespace std + +#endif // MAME_LIB_UTIL_CHD_H diff --git a/src/lib/util/chdcd.cpp b/src/lib/util/chdcd.cpp index ef013b41f48..63b633536bf 100644 --- a/src/lib/util/chdcd.cpp +++ b/src/lib/util/chdcd.cpp @@ -7,15 +7,19 @@ ***************************************************************************/ -#include <cctype> -#include <cstdlib> -#include <cassert> -#include "osdcore.h" -#include "chd.h" #include "chdcd.h" + +#include "chd.h" #include "corefile.h" #include "corestr.h" +#include "osdcore.h" + +#include <cassert> +#include <cctype> +#include <cerrno> +#include <cstdlib> + /*************************************************************************** @@ -230,8 +234,8 @@ static uint32_t parse_wav_sample(const char *filename, uint32_t *dataoffs) uint64_t fsize = 0; std::uint32_t actual; - osd_file::error filerr = osd_file::open(filename, OPEN_FLAG_READ, file, fsize); - if (filerr != osd_file::error::NONE) + std::error_condition const filerr = osd_file::open(filename, OPEN_FLAG_READ, file, fsize); + if (filerr) { printf("ERROR: could not open (%s)\n", filename); return 0; @@ -449,7 +453,7 @@ uint64_t read_uint64(FILE *infile) -------------------------------------------------*/ /** - * @fn chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn std::error_condition chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse nero. * @@ -457,26 +461,25 @@ uint64_t read_uint64(FILE *infile) * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +std::error_condition chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; unsigned char buffer[12]; uint32_t chain_offs, chunk_size; int done = 0; std::string path = std::string(tocfname); - infile = fopen(tocfname, "rb"); - path = get_file_path(path); - - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rb"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -489,7 +492,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ { printf("ERROR: Not a Nero 5.5 or later image!\n"); fclose(infile); - return CHDERR_UNSUPPORTED_VERSION; + return chd_file::error::UNSUPPORTED_FORMAT; } chain_offs = buffer[11] | (buffer[10]<<8) | (buffer[9]<<16) | (buffer[8]<<24); @@ -498,7 +501,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ { printf("ERROR: File size is > 4GB, this version of CHDMAN cannot handle it."); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } // printf("NER5 detected, chain offset: %x\n", chain_offs); @@ -559,12 +562,12 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ case 0x0300: // Mode 2 Form 1 printf("ERROR: Mode 2 Form 1 tracks not supported\n"); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; case 0x0500: // raw data printf("ERROR: Raw data tracks not supported\n"); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; case 0x0600: // 2352 byte mode 2 raw outtoc.tracks[track-1].trktype = CD_TRACK_MODE2_RAW; @@ -579,22 +582,22 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ case 0x0f00: // raw data with sub-channel printf("ERROR: Raw data tracks with sub-channel not supported\n"); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; case 0x1000: // audio with sub-channel printf("ERROR: Audio tracks with sub-channel not supported\n"); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; case 0x1100: // raw Mode 2 Form 1 with sub-channel printf("ERROR: Raw Mode 2 Form 1 tracks with sub-channel not supported\n"); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; default: printf("ERROR: Unknown track type %x, contact MAMEDEV!\n", mode); fclose(infile); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } outtoc.tracks[track-1].datasize = size; @@ -627,7 +630,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ fclose(infile); - return CHDERR_NONE; + return std::error_condition(); } /*------------------------------------------------- @@ -635,7 +638,7 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ -------------------------------------------------*/ /** - * @fn chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn std::error_condition chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse ISO. * @@ -643,22 +646,21 @@ chd_error chdcd_parse_nero(const char *tocfname, cdrom_toc &outtoc, chdcd_track_ * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +std::error_condition chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; std::string path = std::string(tocfname); - infile = fopen(tocfname, "rb"); - path = get_file_path(path); - - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rb"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -693,7 +695,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i outinfo.track[0].swap = false; } else { printf("ERROR: Unrecognized track type\n"); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } outtoc.tracks[0].subtype = CD_SUB_NONE; @@ -709,7 +711,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i outtoc.tracks[0].padframes = 0; - return CHDERR_NONE; + return std::error_condition(); } /*------------------------------------------------- @@ -717,7 +719,7 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i -------------------------------------------------*/ /** - * @fn static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn static std::error_condition chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse GDI. * @@ -725,24 +727,23 @@ chd_error chdcd_parse_iso(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. */ -static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +static std::error_condition chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; int i, numtracks; std::string path = std::string(tocfname); - infile = fopen(tocfname, "rt"); - path = get_file_path(path); - - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rt"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -841,7 +842,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_ /* store the number of tracks found */ outtoc.numtrks = numtracks; - return CHDERR_NONE; + return std::error_condition(); } /*------------------------------------------------- @@ -849,7 +850,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_ -------------------------------------------------*/ /** - * @fn chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn std::error_condition chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse cue. * @@ -857,25 +858,25 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_ * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +std::error_condition chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; int i, trknum; static char token[512]; std::string lastfname; uint32_t wavlen, wavoffs; std::string path = std::string(tocfname); - infile = fopen(tocfname, "rt"); - path = get_file_path(path); - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rt"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -921,14 +922,14 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i { fclose(infile); printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str()); - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; } } else { fclose(infile); printf("ERROR: Unhandled track type %s\n", token); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } } else if (!strcmp(token, "TRACK")) @@ -970,7 +971,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i { fclose(infile); printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } /* next (optional) token on the line is the subcode type */ @@ -1083,7 +1084,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize); outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); @@ -1094,7 +1095,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); outtoc.tracks[trknum].frames = tlen; @@ -1120,7 +1121,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i if (!outtoc.tracks[trknum].frames) { printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; } } else /* data files are different */ @@ -1129,7 +1130,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); outtoc.tracks[trknum].frames = tlen; @@ -1140,7 +1141,7 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i //printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc.tracks[trknum].frames, outinfo.track[trknum].offset); } - return CHDERR_NONE; + return std::error_condition(); } /*--------------------------------------------------------------------------------------- @@ -1161,18 +1162,18 @@ chd_error chdcd_parse_cue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i bool chdcd_is_gdicue(const char *tocfname) { - FILE *infile; bool has_rem_singledensity = false; bool has_rem_highdensity = false; std::string path = std::string(tocfname); - infile = fopen(tocfname, "rt"); - path = get_file_path(path); - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rt"); + if (!infile) { return false; } + path = get_file_path(path); + while (!feof(infile)) { fgets(linebuffer, 511, infile); @@ -1195,7 +1196,7 @@ bool chdcd_is_gdicue(const char *tocfname) ------------------------------------------------------------------*/ /** - * @fn chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn std::error_condition chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse cue. * @@ -1203,7 +1204,7 @@ bool chdcd_is_gdicue(const char *tocfname) * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. * * Dreamcast discs have two images on a single disc. The first image is SINGLE-DENSITY and the second image * is HIGH-DENSITY. The SINGLE-DENSITY area starts 0 LBA and HIGH-DENSITY area starts 45000 LBA. @@ -1218,9 +1219,8 @@ bool chdcd_is_gdicue(const char *tocfname) * layout from a TOSEC .gdi. */ -chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +std::error_condition chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; int i, trknum; static char token[512]; std::string lastfname; @@ -1229,13 +1229,14 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac enum gdi_area current_area = SINGLE_DENSITY; enum gdi_pattern disc_pattern = TYPE_UNKNOWN; - infile = fopen(tocfname, "rt"); - path = get_file_path(path); - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rt"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -1297,14 +1298,14 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac { fclose(infile); printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str()); - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; } } else { fclose(infile); printf("ERROR: Unhandled track type %s\n", token); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } } else if (!strcmp(token, "TRACK")) @@ -1349,7 +1350,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac { fclose(infile); printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } /* next (optional) token on the line is the subcode type */ @@ -1462,7 +1463,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize); outtoc.tracks[trknum].frames = (tlen - outinfo.track[trknum].offset) / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); @@ -1473,7 +1474,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); outtoc.tracks[trknum].frames = tlen; @@ -1499,7 +1500,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac if (!outtoc.tracks[trknum].frames) { printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); - return CHDERR_INVALID_DATA; + return chd_file::error::INVALID_DATA; } } else /* data files are different */ @@ -1508,7 +1509,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac if (tlen == 0) { printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str()); - return CHDERR_FILE_NOT_FOUND; + return std::errc::no_such_file_or_directory; } tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); outtoc.tracks[trknum].frames = tlen; @@ -1638,7 +1639,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac } #endif - return CHDERR_NONE; + return std::error_condition(); } /*------------------------------------------------- @@ -1646,7 +1647,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac -------------------------------------------------*/ /** - * @fn chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) + * @fn std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) * * @brief Chdcd parse TOC. * @@ -1654,12 +1655,11 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac * @param [in,out] outtoc The outtoc. * @param [in,out] outinfo The outinfo. * - * @return A chd_error. + * @return A std::error_condition. */ -chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) +std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo) { - FILE *infile; int i, trknum; static char token[512]; char tocftemp[512]; @@ -1695,14 +1695,14 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i std::string path = std::string(tocfname); - infile = fopen(tocfname, "rt"); - path = get_file_path(path); - - if (infile == (FILE *)nullptr) + FILE *infile = fopen(tocfname, "rt"); + if (!infile) { - return CHDERR_FILE_NOT_FOUND; + return std::error_condition(errno, std::generic_category()); } + path = get_file_path(path); + /* clear structures */ memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); @@ -1817,7 +1817,7 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i { fclose(infile); printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return CHDERR_UNSUPPORTED_FORMAT; + return chd_file::error::UNSUPPORTED_FORMAT; } /* next (optional) token on the line is the subcode type */ @@ -1844,5 +1844,5 @@ chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_i /* store the number of tracks found */ outtoc.numtrks = trknum + 1; - return CHDERR_NONE; + return std::error_condition(); } diff --git a/src/lib/util/chdcd.h b/src/lib/util/chdcd.h index 65e4b943964..95f214e5831 100644 --- a/src/lib/util/chdcd.h +++ b/src/lib/util/chdcd.h @@ -5,14 +5,16 @@ CDRDAO TOC parser for CHD compression frontend ***************************************************************************/ - -#ifndef MAME_UTIL_CHDCD_H -#define MAME_UTIL_CHDCD_H +#ifndef MAME_LIB_UTIL_CHDCD_H +#define MAME_LIB_UTIL_CHDCD_H #pragma once #include "cdrom.h" +#include <system_error> + + struct chdcd_track_input_entry { chdcd_track_input_entry() { reset(); } @@ -33,6 +35,6 @@ struct chdcd_track_input_info }; -chd_error chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo); +std::error_condition chdcd_parse_toc(const char *tocfname, cdrom_toc &outtoc, chdcd_track_input_info &outinfo); -#endif // MAME_UTIL_CHDCD_H +#endif // MAME_LIB_UTIL_CHDCD_H diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp index 4f5c23b3104..eca9403b56c 100644 --- a/src/lib/util/chdcodec.cpp +++ b/src/lib/util/chdcodec.cpp @@ -8,24 +8,29 @@ ***************************************************************************/ -#include <cassert> +#include "chdcodec.h" -#include "chd.h" -#include "hashing.h" #include "avhuff.h" -#include "flac.h" #include "cdrom.h" -#include <zlib.h> -#include "lzma/C/LzmaEnc.h" +#include "chd.h" +#include "flac.h" +#include "hashing.h" + #include "lzma/C/LzmaDec.h" +#include "lzma/C/LzmaEnc.h" + +#include <zlib.h> + #include <new> +namespace { + //************************************************************************** // GLOBAL VARIABLES //************************************************************************** -static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; +constexpr uint8_t f_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; @@ -35,7 +40,7 @@ static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff // ======================> chd_zlib_allocator -// allocation helper clas for zlib +// allocation helper class for zlib class chd_zlib_allocator { public: @@ -51,7 +56,8 @@ private: static voidpf fast_alloc(voidpf opaque, uInt items, uInt size); static void fast_free(voidpf opaque, voidpf address); - static const int MAX_ZLIB_ALLOCS = 64; + static constexpr int MAX_ZLIB_ALLOCS = 64; + uint32_t * m_allocptr[MAX_ZLIB_ALLOCS]; }; @@ -111,7 +117,7 @@ private: static void *fast_alloc(void *p, size_t size); static void fast_free(void *p, void *address); - static const int MAX_LZMA_ALLOCS = 64; + static constexpr int MAX_LZMA_ALLOCS = 64; uint32_t * m_allocptr[MAX_LZMA_ALLOCS]; }; @@ -287,7 +293,7 @@ private: // ======================> chd_cd_compressor -template<class _BaseCompressor, class _SubcodeCompressor> +template<class BaseCompressor, class SubcodeCompressor> class chd_cd_compressor : public chd_compressor { public: @@ -300,7 +306,7 @@ public: { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } // core functionality @@ -323,10 +329,10 @@ public: // clear out ECC data if we can uint8_t *sector = &m_buffer[framenum * CD_MAX_SECTOR_DATA]; - if (memcmp(sector, s_cd_sync_header, sizeof(s_cd_sync_header)) == 0 && ecc_verify(sector)) + if (memcmp(sector, f_cd_sync_header, sizeof(f_cd_sync_header)) == 0 && ecc_verify(sector)) { dest[framenum / 8] |= 1 << (framenum % 8); - memset(sector, 0, sizeof(s_cd_sync_header)); + memset(sector, 0, sizeof(f_cd_sync_header)); ecc_clear(sector); } } @@ -334,7 +340,7 @@ public: // encode the base portion uint32_t complen = m_base_compressor.compress(&m_buffer[0], frames * CD_MAX_SECTOR_DATA, &dest[header_bytes]); if (complen >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // write compressed length dest[ecc_bytes + 0] = complen >> ((complen_bytes - 1) * 8); @@ -348,15 +354,15 @@ public: private: // internal state - _BaseCompressor m_base_compressor; - _SubcodeCompressor m_subcode_compressor; + BaseCompressor m_base_compressor; + SubcodeCompressor m_subcode_compressor; std::vector<uint8_t> m_buffer; }; // ======================> chd_cd_decompressor -template<class _BaseDecompressor, class _SubcodeDecompressor> +template<class BaseDecompressor, class SubcodeDecompressor> class chd_cd_decompressor : public chd_decompressor { public: @@ -369,7 +375,7 @@ public: { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } // core functionality @@ -400,7 +406,7 @@ public: uint8_t *sector = &dest[framenum * CD_FRAME_SIZE]; if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) { - memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + memcpy(sector, f_cd_sync_header, sizeof(f_cd_sync_header)); ecc_generate(sector); } } @@ -408,8 +414,8 @@ public: private: // internal state - _BaseDecompressor m_base_decompressor; - _SubcodeDecompressor m_subcode_decompressor; + BaseDecompressor m_base_decompressor; + SubcodeDecompressor m_subcode_decompressor; std::vector<uint8_t> m_buffer; }; @@ -460,25 +466,65 @@ private: // CODEC LIST //************************************************************************** +// an entry in the list +struct codec_entry +{ + chd_codec_type m_type; + bool m_lossy; + const char * m_name; + chd_compressor::ptr (*m_construct_compressor)(chd_file &, uint32_t, bool); + chd_decompressor::ptr (*m_construct_decompressor)(chd_file &, uint32_t, bool); + + template <class CompressorClass> + static chd_compressor::ptr construct_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + { + return std::make_unique<CompressorClass>(chd, hunkbytes, lossy); + } + + template <class DecompressorClass> + static chd_decompressor::ptr construct_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) + { + return std::make_unique<DecompressorClass>(chd, hunkbytes, lossy); + } +}; + + // static list of available known codecs -const chd_codec_list::codec_entry chd_codec_list::s_codec_list[] = +const codec_entry f_codec_list[] = { // general codecs - { CHD_CODEC_ZLIB, false, "Deflate", &chd_codec_list::construct_compressor<chd_zlib_compressor>, &chd_codec_list::construct_decompressor<chd_zlib_decompressor> }, - { CHD_CODEC_LZMA, false, "LZMA", &chd_codec_list::construct_compressor<chd_lzma_compressor>, &chd_codec_list::construct_decompressor<chd_lzma_decompressor> }, - { CHD_CODEC_HUFFMAN, false, "Huffman", &chd_codec_list::construct_compressor<chd_huffman_compressor>, &chd_codec_list::construct_decompressor<chd_huffman_decompressor> }, - { CHD_CODEC_FLAC, false, "FLAC", &chd_codec_list::construct_compressor<chd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_flac_decompressor> }, + { CHD_CODEC_ZLIB, false, "Deflate", &codec_entry::construct_compressor<chd_zlib_compressor>, &codec_entry::construct_decompressor<chd_zlib_decompressor> }, + { CHD_CODEC_LZMA, false, "LZMA", &codec_entry::construct_compressor<chd_lzma_compressor>, &codec_entry::construct_decompressor<chd_lzma_decompressor> }, + { CHD_CODEC_HUFFMAN, false, "Huffman", &codec_entry::construct_compressor<chd_huffman_compressor>, &codec_entry::construct_decompressor<chd_huffman_decompressor> }, + { CHD_CODEC_FLAC, false, "FLAC", &codec_entry::construct_compressor<chd_flac_compressor>, &codec_entry::construct_decompressor<chd_flac_decompressor> }, // general codecs with CD frontend - { CHD_CODEC_CD_ZLIB, false, "CD Deflate", &chd_codec_list::construct_compressor<chd_cd_compressor<chd_zlib_compressor, chd_zlib_compressor> >, &chd_codec_list::construct_decompressor<chd_cd_decompressor<chd_zlib_decompressor, chd_zlib_decompressor> > }, - { CHD_CODEC_CD_LZMA, false, "CD LZMA", &chd_codec_list::construct_compressor<chd_cd_compressor<chd_lzma_compressor, chd_zlib_compressor> >, &chd_codec_list::construct_decompressor<chd_cd_decompressor<chd_lzma_decompressor, chd_zlib_decompressor> > }, - { CHD_CODEC_CD_FLAC, false, "CD FLAC", &chd_codec_list::construct_compressor<chd_cd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_cd_flac_decompressor> }, + { CHD_CODEC_CD_ZLIB, false, "CD Deflate", &codec_entry::construct_compressor<chd_cd_compressor<chd_zlib_compressor, chd_zlib_compressor> >, &codec_entry::construct_decompressor<chd_cd_decompressor<chd_zlib_decompressor, chd_zlib_decompressor> > }, + { CHD_CODEC_CD_LZMA, false, "CD LZMA", &codec_entry::construct_compressor<chd_cd_compressor<chd_lzma_compressor, chd_zlib_compressor> >, &codec_entry::construct_decompressor<chd_cd_decompressor<chd_lzma_decompressor, chd_zlib_decompressor> > }, + { CHD_CODEC_CD_FLAC, false, "CD FLAC", &codec_entry::construct_compressor<chd_cd_flac_compressor>, &codec_entry::construct_decompressor<chd_cd_flac_decompressor> }, // A/V codecs - { CHD_CODEC_AVHUFF, false, "A/V Huffman", &chd_codec_list::construct_compressor<chd_avhuff_compressor>, &chd_codec_list::construct_decompressor<chd_avhuff_decompressor> }, + { CHD_CODEC_AVHUFF, false, "A/V Huffman", &codec_entry::construct_compressor<chd_avhuff_compressor>, &codec_entry::construct_decompressor<chd_avhuff_decompressor> }, }; +//------------------------------------------------- +// find_in_list - create a new compressor +// instance of the given type +//------------------------------------------------- + +const codec_entry *find_in_list(chd_codec_type type) +{ + // find in the list and construct the class + for (auto & elem : f_codec_list) + if (elem.m_type == type) + return &elem; + return nullptr; +} + +} // anonymous namespace + + //************************************************************************** // CHD CODEC @@ -512,7 +558,7 @@ chd_codec::~chd_codec() void chd_codec::configure(int param, void *config) { // if not overridden, it is always a failure - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); } @@ -556,11 +602,11 @@ chd_decompressor::chd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy // instance of the given type //------------------------------------------------- -chd_compressor *chd_codec_list::new_compressor(chd_codec_type type, chd_file &chd) +chd_compressor::ptr chd_codec_list::new_compressor(chd_codec_type type, chd_file &chd) { // find in the list and construct the class - const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : (*entry->m_construct_compressor)(chd, chd.hunk_bytes(), entry->m_lossy); + codec_entry const *const entry = find_in_list(type); + return entry ? (*entry->m_construct_compressor)(chd, chd.hunk_bytes(), entry->m_lossy) : nullptr; } @@ -569,39 +615,36 @@ chd_compressor *chd_codec_list::new_compressor(chd_codec_type type, chd_file &ch // instance of the given type //------------------------------------------------- -chd_decompressor *chd_codec_list::new_decompressor(chd_codec_type type, chd_file &chd) +chd_decompressor::ptr chd_codec_list::new_decompressor(chd_codec_type type, chd_file &chd) { // find in the list and construct the class const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : (*entry->m_construct_decompressor)(chd, chd.hunk_bytes(), entry->m_lossy); + return entry ? (*entry->m_construct_decompressor)(chd, chd.hunk_bytes(), entry->m_lossy) : nullptr; } //------------------------------------------------- -// codec_name - return the name of the given -// codec +// codec_exists - determine whether a codec type +// corresponds to a supported codec //------------------------------------------------- -const char *chd_codec_list::codec_name(chd_codec_type type) +bool chd_codec_list::codec_exists(chd_codec_type type) { // find in the list and construct the class - const codec_entry *entry = find_in_list(type); - return (entry == nullptr) ? nullptr : entry->m_name; + return bool(find_in_list(type)); } //------------------------------------------------- -// find_in_list - create a new compressor -// instance of the given type +// codec_name - return the name of the given +// codec //------------------------------------------------- -const chd_codec_list::codec_entry *chd_codec_list::find_in_list(chd_codec_type type) +const char *chd_codec_list::codec_name(chd_codec_type type) { // find in the list and construct the class - for (auto & elem : s_codec_list) - if (elem.m_type == type) - return &elem; - return nullptr; + const codec_entry *entry = find_in_list(type); + return entry ? entry->m_name : nullptr; } @@ -615,25 +658,24 @@ const chd_codec_list::codec_entry *chd_codec_list::find_in_list(chd_codec_type t //------------------------------------------------- chd_compressor_group::chd_compressor_group(chd_file &chd, uint32_t compressor_list[4]) - : m_hunkbytes(chd.hunk_bytes()), - m_compress_test(m_hunkbytes) + : m_hunkbytes(chd.hunk_bytes()) + , m_compress_test(m_hunkbytes) #if CHDCODEC_VERIFY_COMPRESSION - ,m_decompressed(m_hunkbytes) + , m_decompressed(m_hunkbytes) #endif { // verify the compression types and initialize the codecs for (int codecnum = 0; codecnum < std::size(m_compressor); codecnum++) { - m_compressor[codecnum] = nullptr; if (compressor_list[codecnum] != CHD_CODEC_NONE) { m_compressor[codecnum] = chd_codec_list::new_compressor(compressor_list[codecnum], chd); - if (m_compressor[codecnum] == nullptr) - throw CHDERR_UNKNOWN_COMPRESSION; + if (!m_compressor[codecnum]) + throw std::error_condition(chd_file::error::UNKNOWN_COMPRESSION); #if CHDCODEC_VERIFY_COMPRESSION m_decompressor[codecnum] = chd_codec_list::new_decompressor(compressor_list[codecnum], chd); - if (m_decompressor[codecnum] == nullptr) - throw CHDERR_UNKNOWN_COMPRESSION; + if (!m_decompressor[codecnum]) + throw std::error_condition(chd_file::error::UNKNOWN_COMPRESSION); #endif } } @@ -646,9 +688,7 @@ chd_compressor_group::chd_compressor_group(chd_file &chd, uint32_t compressor_li chd_compressor_group::~chd_compressor_group() { - // delete the codecs and the test buffer - for (auto & elem : m_compressor) - delete elem; + // codecs and test buffer deleted automatically } @@ -664,7 +704,7 @@ int8_t chd_compressor_group::find_best_compressor(const uint8_t *src, uint8_t *c complen = m_hunkbytes; int8_t compression = -1; for (int codecnum = 0; codecnum < std::size(m_compressor); codecnum++) - if (m_compressor[codecnum] != nullptr) + if (m_compressor[codecnum]) { // attempt to compress, swallowing errors try @@ -702,7 +742,9 @@ printf(" codec%d=%d bytes \n", codecnum, compbytes); memcpy(compressed, &m_compress_test[0], compbytes); } } - catch (...) { } + catch (...) + { + } } // if the best is none, copy it over @@ -835,7 +877,7 @@ chd_zlib_compressor::chd_zlib_compressor(chd_file &chd, uint32_t hunkbytes, bool if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -864,14 +906,14 @@ uint32_t chd_zlib_compressor::compress(const uint8_t *src, uint32_t srclen, uint m_deflater.total_out = 0; int zerr = deflateReset(&m_deflater); if (zerr != Z_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // do it zerr = deflate(&m_deflater, Z_FINISH); // if we ended up with more data than we started with, return an error if (zerr != Z_STREAM_END || m_deflater.total_out >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // otherwise, return the length return m_deflater.total_out; @@ -900,7 +942,7 @@ chd_zlib_decompressor::chd_zlib_decompressor(chd_file &chd, uint32_t hunkbytes, if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -930,14 +972,14 @@ void chd_zlib_decompressor::decompress(const uint8_t *src, uint32_t complen, uin m_inflater.total_out = 0; int zerr = inflateReset(&m_inflater); if (zerr != Z_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // do it zerr = inflate(&m_inflater, Z_FINISH); if (zerr != Z_STREAM_END) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (m_inflater.total_out != destlen) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -1071,20 +1113,20 @@ uint32_t chd_lzma_compressor::compress(const uint8_t *src, uint32_t srclen, uint // allocate the encoder CLzmaEncHandle encoder = LzmaEnc_Create(&m_allocator); if (encoder == nullptr) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); try { // configure the encoder SRes res = LzmaEnc_SetProps(encoder, &m_props); if (res != SZ_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // run it SizeT complen = srclen; res = LzmaEnc_MemEncode(encoder, dest, &complen, src, srclen, 0, nullptr, &m_allocator, &m_allocator); if (res != SZ_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // clean up LzmaEnc_Destroy(encoder, &m_allocator, &m_allocator); @@ -1140,24 +1182,24 @@ chd_lzma_decompressor::chd_lzma_decompressor(chd_file &chd, uint32_t hunkbytes, // convert to decoder properties CLzmaEncHandle enc = LzmaEnc_Create(&m_allocator); if (!enc) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) { LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } Byte decoder_props[LZMA_PROPS_SIZE]; SizeT props_size = sizeof(decoder_props); if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) { LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } LzmaEnc_Destroy(enc, &m_allocator, &m_allocator); // do memory allocations if (LzmaDec_Allocate(&m_decoder, decoder_props, LZMA_PROPS_SIZE, &m_allocator) != SZ_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -1188,7 +1230,7 @@ void chd_lzma_decompressor::decompress(const uint8_t *src, uint32_t complen, uin ELzmaStatus status; SRes res = LzmaDec_DecodeToBuf(&m_decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); } @@ -1216,7 +1258,7 @@ uint32_t chd_huffman_compressor::compress(const uint8_t *src, uint32_t srclen, u { uint32_t complen; if (m_encoder.encode(src, srclen, dest, srclen, complen) != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1244,7 +1286,7 @@ chd_huffman_decompressor::chd_huffman_decompressor(chd_file &chd, uint32_t hunkb void chd_huffman_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { if (m_decoder.decode(src, complen, dest, destlen) != HUFFERR_NONE) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); } @@ -1282,19 +1324,19 @@ uint32_t chd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, uint // reset and encode big-endian m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, !m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); uint32_t complen_be = m_encoder.finish(); // reset and encode little-endian m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); uint32_t complen_le = m_encoder.finish(); // pick the best one and add a byte uint32_t complen = std::min(complen_le, complen_be); if (complen + 1 >= hunkbytes()) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // if big-endian was better, re-do it dest[0] = 'L'; @@ -1303,7 +1345,7 @@ uint32_t chd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, uint dest[0] = 'B'; m_encoder.reset(dest + 1, hunkbytes() - 1); if (!m_encoder.encode_interleaved(reinterpret_cast<const int16_t *>(src), srclen / 4, !m_big_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); m_encoder.finish(); } return complen + 1; @@ -1358,13 +1400,13 @@ void chd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uin else if (src[0] == 'B') swap_endian = !m_big_endian; else - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // reset and decode if (!m_decoder.reset(44100, 2, chd_flac_compressor::blocksize(destlen), src + 1, complen - 1)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (!m_decoder.decode_interleaved(reinterpret_cast<int16_t *>(dest), destlen / 4, swap_endian)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // finish up m_decoder.finish(); @@ -1386,7 +1428,7 @@ chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); // determine whether we want native or swapped samples uint16_t native_endian = 0; @@ -1409,7 +1451,7 @@ chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } @@ -1442,7 +1484,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u m_encoder.reset(dest, hunkbytes()); uint8_t *buffer = &m_buffer[0]; if (!m_encoder.encode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * CD_MAX_SECTOR_DATA/4, m_swap_endian)) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // finish up uint32_t complen = m_encoder.finish(); @@ -1456,7 +1498,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u m_deflater.total_out = 0; int zerr = deflateReset(&m_deflater); if (zerr != Z_OK) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); // do it zerr = deflate(&m_deflater, Z_FINISH); @@ -1464,7 +1506,7 @@ uint32_t chd_cd_flac_compressor::compress(const uint8_t *src, uint32_t srclen, u // if we ended up with more data than we started with, return an error complen += m_deflater.total_out; if (zerr != Z_STREAM_END || complen >= srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1515,7 +1557,7 @@ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkb { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % CD_FRAME_SIZE != 0) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); // determine whether we want native or swapped samples uint16_t native_endian = 0; @@ -1532,7 +1574,7 @@ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkb if (zerr == Z_MEM_ERROR) throw std::bad_alloc(); else if (zerr != Z_OK) - throw CHDERR_CODEC_ERROR; + throw std::error_condition(chd_file::error::CODEC_ERROR); } /** @@ -1569,10 +1611,10 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, // reset and decode uint32_t frames = destlen / CD_FRAME_SIZE; if (!m_decoder.reset(44100, 2, chd_cd_flac_compressor::blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); uint8_t *buffer = &m_buffer[0]; if (!m_decoder.decode_interleaved(reinterpret_cast<int16_t *>(buffer), frames * CD_MAX_SECTOR_DATA/4, m_swap_endian)) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // inflate the subcode data uint32_t offset = m_decoder.finish(); @@ -1584,14 +1626,14 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, m_inflater.total_out = 0; int zerr = inflateReset(&m_inflater); if (zerr != Z_OK) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // do it zerr = inflate(&m_inflater, Z_FINISH); if (zerr != Z_STREAM_END) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); if (m_inflater.total_out != frames * CD_MAX_SUBCODE_DATA) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // reassemble the data for (uint32_t framenum = 0; framenum < frames; framenum++) @@ -1620,15 +1662,15 @@ void chd_cd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, */ chd_avhuff_compressor::chd_avhuff_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_postinit(false) + : chd_compressor(chd, hunkbytes, lossy) + , m_postinit(false) { try { // attempt to do a post-init now postinit(); } - catch (chd_error &) + catch (std::error_condition const &) { // if we're creating a new CHD, it won't work but that's ok } @@ -1665,14 +1707,14 @@ uint32_t chd_avhuff_compressor::compress(const uint8_t *src, uint32_t srclen, ui int size = avhuff_encoder::raw_data_size(src); while (size < srclen) if (src[size++] != 0) - throw CHDERR_INVALID_DATA; + throw std::error_condition(chd_file::error::INVALID_DATA); } // encode the audio and video uint32_t complen; avhuff_error averr = m_encoder.encode_data(src, dest, complen); if (averr != AVHERR_NONE || complen > srclen) - throw CHDERR_COMPRESSION_ERROR; + throw std::error_condition(chd_file::error::COMPRESSION_ERROR); return complen; } @@ -1693,21 +1735,21 @@ void chd_avhuff_compressor::postinit() { // get the metadata std::string metadata; - chd_error err = chd().read_metadata(AV_METADATA_TAG, 0, metadata); - if (err != CHDERR_NONE) + std::error_condition err = chd().read_metadata(AV_METADATA_TAG, 0, metadata); + if (err) throw err; // extract the info int fps, fpsfrac, width, height, interlaced, channels, rate; if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate) != 7) - throw CHDERR_INVALID_METADATA; + throw std::error_condition(chd_file::error::INVALID_METADATA); // compute the bytes per frame uint32_t fps_times_1million = fps * 1000000 + fpsfrac; uint32_t max_samples_per_frame = (uint64_t(rate) * 1000000 + fps_times_1million - 1) / fps_times_1million; uint32_t bytes_per_frame = 12 + channels * max_samples_per_frame * 2 + width * height * 2; if (bytes_per_frame > hunkbytes()) - throw CHDERR_INVALID_METADATA; + throw std::error_condition(chd_file::error::INVALID_METADATA); // done with post-init m_postinit = true; @@ -1757,7 +1799,7 @@ void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, u // decode the audio and video avhuff_error averr = m_decoder.decode_data(src, complen, dest); if (averr != AVHERR_NONE) - throw CHDERR_DECOMPRESSION_ERROR; + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // pad short frames with 0 if (dest != nullptr) @@ -1790,5 +1832,5 @@ void chd_avhuff_decompressor::configure(int param, void *config) // anything else is invalid else - throw CHDERR_INVALID_PARAMETER; + throw std::error_condition(std::errc::invalid_argument); } diff --git a/src/lib/util/chdcodec.h b/src/lib/util/chdcodec.h index dc9c074fd37..700ae8f8979 100644 --- a/src/lib/util/chdcodec.h +++ b/src/lib/util/chdcodec.h @@ -7,13 +7,15 @@ Codecs used by the CHD format ***************************************************************************/ - -#ifndef MAME_UTIL_CHDCODEC_H -#define MAME_UTIL_CHDCODEC_H +#ifndef MAME_LIB_UTIL_CHDCODEC_H +#define MAME_LIB_UTIL_CHDCODEC_H #pragma once +#include "utilfwd.h" + #include <cstdint> +#include <memory> #include <vector> @@ -21,20 +23,9 @@ //************************************************************************** -// MACROS -//************************************************************************** - -#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) - - - -//************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// forward references -class chd_file; - // base types typedef uint32_t chd_codec_type; @@ -63,7 +54,7 @@ public: private: // internal state chd_file & m_chd; - uint32_t m_hunkbytes; + uint32_t m_hunkbytes; bool m_lossy; }; @@ -78,6 +69,8 @@ protected: chd_compressor(chd_file &file, uint32_t hunkbytes, bool lossy); public: + using ptr = std::unique_ptr<chd_compressor>; + // implementation virtual uint32_t compress(const uint8_t *src, uint32_t srclen, uint8_t *dest) = 0; }; @@ -93,6 +86,8 @@ protected: chd_decompressor(chd_file &file, uint32_t hunkbytes, bool lossy); public: + using ptr = std::unique_ptr<chd_decompressor>; + // implementation virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) = 0; }; @@ -105,35 +100,12 @@ class chd_codec_list { public: // create compressors or decompressors - static chd_compressor *new_compressor(chd_codec_type type, chd_file &file); - static chd_decompressor *new_decompressor(chd_codec_type type, chd_file &file); + static chd_compressor::ptr new_compressor(chd_codec_type type, chd_file &file); + static chd_decompressor::ptr new_decompressor(chd_codec_type type, chd_file &file); // utilities - static bool codec_exists(chd_codec_type type) { return (find_in_list(type) != nullptr); } + static bool codec_exists(chd_codec_type type); static const char *codec_name(chd_codec_type type); - -private: - // an entry in the list - struct codec_entry - { - chd_codec_type m_type; - bool m_lossy; - const char * m_name; - chd_compressor * (*m_construct_compressor)(chd_file &, uint32_t, bool); - chd_decompressor * (*m_construct_decompressor)(chd_file &, uint32_t, bool); - }; - - // internal helper functions - static const codec_entry *find_in_list(chd_codec_type type); - - template<class _CompressorClass> - static chd_compressor *construct_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) { return new _CompressorClass(chd, hunkbytes, lossy); } - - template<class _DecompressorClass> - static chd_decompressor *construct_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) { return new _DecompressorClass(chd, hunkbytes, lossy); } - - // the static list - static const codec_entry s_codec_list[]; }; @@ -152,37 +124,48 @@ public: private: // internal state - uint32_t m_hunkbytes; // number of bytes in a hunk - chd_compressor * m_compressor[4]; // array of active codecs - std::vector<uint8_t> m_compress_test; // test buffer for compression + uint32_t m_hunkbytes; // number of bytes in a hunk + chd_compressor::ptr m_compressor[4]; // array of active codecs + std::vector<uint8_t> m_compress_test; // test buffer for compression #if CHDCODEC_VERIFY_COMPRESSION - chd_decompressor * m_decompressor[4]; // array of active codecs - std::vector<uint8_t> m_decompressed; // verification buffer + chd_decompressor::ptr m_decompressor[4]; // array of active codecs + std::vector<uint8_t> m_decompressed; // verification buffer #endif }; //************************************************************************** +// MACROS +//************************************************************************** + +constexpr chd_codec_type CHD_MAKE_TAG(char a, char b, char c, char d) +{ + return (uint32_t(uint8_t(a)) << 24) | uint32_t(uint8_t((b)) << 16) | uint32_t(uint8_t((c)) << 8) | uint32_t(uint8_t(d)); +} + + + +//************************************************************************** // CONSTANTS //************************************************************************** // currently-defined codecs -const chd_codec_type CHD_CODEC_NONE = 0; +constexpr chd_codec_type CHD_CODEC_NONE = 0; // general codecs -const chd_codec_type CHD_CODEC_ZLIB = CHD_MAKE_TAG('z','l','i','b'); -const chd_codec_type CHD_CODEC_LZMA = CHD_MAKE_TAG('l','z','m','a'); -const chd_codec_type CHD_CODEC_HUFFMAN = CHD_MAKE_TAG('h','u','f','f'); -const chd_codec_type CHD_CODEC_FLAC = CHD_MAKE_TAG('f','l','a','c'); +constexpr chd_codec_type CHD_CODEC_ZLIB = CHD_MAKE_TAG('z','l','i','b'); +constexpr chd_codec_type CHD_CODEC_LZMA = CHD_MAKE_TAG('l','z','m','a'); +constexpr chd_codec_type CHD_CODEC_HUFFMAN = CHD_MAKE_TAG('h','u','f','f'); +constexpr chd_codec_type CHD_CODEC_FLAC = CHD_MAKE_TAG('f','l','a','c'); // general codecs with CD frontend -const chd_codec_type CHD_CODEC_CD_ZLIB = CHD_MAKE_TAG('c','d','z','l'); -const chd_codec_type CHD_CODEC_CD_LZMA = CHD_MAKE_TAG('c','d','l','z'); -const chd_codec_type CHD_CODEC_CD_FLAC = CHD_MAKE_TAG('c','d','f','l'); +constexpr chd_codec_type CHD_CODEC_CD_ZLIB = CHD_MAKE_TAG('c','d','z','l'); +constexpr chd_codec_type CHD_CODEC_CD_LZMA = CHD_MAKE_TAG('c','d','l','z'); +constexpr chd_codec_type CHD_CODEC_CD_FLAC = CHD_MAKE_TAG('c','d','f','l'); // A/V codecs -const chd_codec_type CHD_CODEC_AVHUFF = CHD_MAKE_TAG('a','v','h','u'); +constexpr chd_codec_type CHD_CODEC_AVHUFF = CHD_MAKE_TAG('a','v','h','u'); // A/V codec configuration parameters enum @@ -190,4 +173,4 @@ enum AVHUFF_CODEC_DECOMPRESS_CONFIG = 1 }; -#endif // MAME_UTIL_CHDCODEC_H +#endif // MAME_LIB_UTIL_CHDCODEC_H diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp index e681c0f1fac..0c72e1337be 100644 --- a/src/lib/util/corefile.cpp +++ b/src/lib/util/corefile.cpp @@ -12,18 +12,16 @@ #include "coretmpl.h" #include "osdcore.h" +#include "path.h" #include "unicode.h" #include "vecstream.h" -#include <zlib.h> - #include <algorithm> #include <cassert> +#include <cctype> #include <cstring> #include <iterator> -#include <cctype> - namespace util { @@ -43,110 +41,11 @@ namespace { TYPE DEFINITIONS ***************************************************************************/ -class zlib_data -{ -public: - typedef std::unique_ptr<zlib_data> ptr; - - static int start_compression(int level, std::uint64_t offset, ptr &data) - { - ptr result(new zlib_data(offset)); - result->reset_output(); - auto const zerr = deflateInit(&result->m_stream, level); - result->m_compress = (Z_OK == zerr); - if (result->m_compress) data = std::move(result); - return zerr; - } - static int start_decompression(std::uint64_t offset, ptr &data) - { - ptr result(new zlib_data(offset)); - auto const zerr = inflateInit(&result->m_stream); - result->m_decompress = (Z_OK == zerr); - if (result->m_decompress) data = std::move(result); - return zerr; - } - - ~zlib_data() - { - if (m_compress) deflateEnd(&m_stream); - else if (m_decompress) inflateEnd(&m_stream); - } - - std::size_t buffer_size() const { return sizeof(m_buffer); } - void const *buffer_data() const { return m_buffer; } - void *buffer_data() { return m_buffer; } - - // general-purpose output buffer manipulation - bool output_full() const { return 0 == m_stream.avail_out; } - std::size_t output_space() const { return m_stream.avail_out; } - void set_output(void *data, std::uint32_t size) - { - m_stream.next_out = reinterpret_cast<Bytef *>(data); - m_stream.avail_out = size; - } - - // working with output to the internal buffer - bool has_output() const { return m_stream.avail_out != sizeof(m_buffer); } - std::size_t output_size() const { return sizeof(m_buffer) - m_stream.avail_out; } - void reset_output() - { - m_stream.next_out = m_buffer; - m_stream.avail_out = sizeof(m_buffer); - } - - // general-purpose input buffer manipulation - bool has_input() const { return 0 != m_stream.avail_in; } - std::size_t input_size() const { return m_stream.avail_in; } - void set_input(void const *data, std::uint32_t size) - { - m_stream.next_in = const_cast<Bytef *>(reinterpret_cast<Bytef const *>(data)); - m_stream.avail_in = size; - } - - // working with input from the internal buffer - void reset_input(std::uint32_t size) - { - m_stream.next_in = m_buffer; - m_stream.avail_in = size; - } - - int compress() { assert(m_compress); return deflate(&m_stream, Z_NO_FLUSH); } - int finalise() { assert(m_compress); return deflate(&m_stream, Z_FINISH); } - int decompress() { assert(m_decompress); return inflate(&m_stream, Z_SYNC_FLUSH); } - - std::uint64_t realoffset() const { return m_realoffset; } - void add_realoffset(std::uint32_t increment) { m_realoffset += increment; } - - bool is_nextoffset(std::uint64_t value) const { return m_nextoffset == value; } - void add_nextoffset(std::uint32_t increment) { m_nextoffset += increment; } - -private: - zlib_data(std::uint64_t offset) - : m_compress(false) - , m_decompress(false) - , m_realoffset(offset) - , m_nextoffset(offset) - { - m_stream.zalloc = Z_NULL; - m_stream.zfree = Z_NULL; - m_stream.opaque = Z_NULL; - m_stream.avail_in = m_stream.avail_out = 0; - } - - bool m_compress, m_decompress; - z_stream m_stream; - std::uint8_t m_buffer[1024]; - std::uint64_t m_realoffset; - std::uint64_t m_nextoffset; -}; - - class core_proxy_file : public core_file { public: - core_proxy_file(core_file &file) : m_file(file) { } + core_proxy_file(core_file &file) noexcept : m_file(file) { } virtual ~core_proxy_file() override { } - virtual osd_file::error compress(int level) override { return m_file.compress(level); } virtual int seek(std::int64_t offset, int whence) override { return m_file.seek(offset, whence); } virtual std::uint64_t tell() const override { return m_file.tell(); } @@ -162,9 +61,9 @@ public: virtual std::uint32_t write(const void *buffer, std::uint32_t length) override { return m_file.write(buffer, length); } virtual int puts(std::string_view s) override { return m_file.puts(s); } virtual int vprintf(util::format_argument_pack<std::ostream> const &args) override { return m_file.vprintf(args); } - virtual osd_file::error truncate(std::uint64_t offset) override { return m_file.truncate(offset); } + virtual std::error_condition truncate(std::uint64_t offset) override { return m_file.truncate(offset); } - virtual osd_file::error flush() override { return m_file.flush(); } + virtual std::error_condition flush() override { return m_file.flush(); } private: core_file &m_file; @@ -230,12 +129,12 @@ public: if (copy) { void *const buf = allocate(); - if (buf) std::memcpy(buf, data, length); + if (buf) + std::memcpy(buf, data, length); } } ~core_in_memory_file() override { purge(); } - virtual osd_file::error compress(int level) override { return osd_file::error::INVALID_ACCESS; } virtual int seek(std::int64_t offset, int whence) override; virtual std::uint64_t tell() const override { return m_offset; } @@ -246,8 +145,8 @@ public: virtual void const *buffer() override { return m_data; } virtual std::uint32_t write(void const *buffer, std::uint32_t length) override { return 0; } - virtual osd_file::error truncate(std::uint64_t offset) override; - virtual osd_file::error flush() override { clear_putback(); return osd_file::error::NONE; } + virtual std::error_condition truncate(std::uint64_t offset) override; + virtual std::error_condition flush() override { clear_putback(); return std::error_condition(); } protected: core_in_memory_file(std::uint32_t openflags, std::uint64_t length) @@ -262,7 +161,8 @@ protected: bool is_loaded() const { return nullptr != m_data; } void *allocate() { - if (m_data) return nullptr; + if (m_data) + return nullptr; void *data = malloc(m_length); if (data) { @@ -273,7 +173,8 @@ protected: } void purge() { - if (m_data && m_data_allocated) free(const_cast<void *>(m_data)); + if (m_data && m_data_allocated) + free(const_cast<void *>(m_data)); m_data_allocated = false; m_data = nullptr; } @@ -301,23 +202,18 @@ public: core_osd_file(std::uint32_t openmode, osd_file::ptr &&file, std::uint64_t length) : core_in_memory_file(openmode, length) , m_file(std::move(file)) - , m_zdata() , m_bufferbase(0) , m_bufferbytes(0) { } ~core_osd_file() override; - virtual osd_file::error compress(int level) override; - - virtual int seek(std::int64_t offset, int whence) override; - virtual std::uint32_t read(void *buffer, std::uint32_t length) override; virtual void const *buffer() override; virtual std::uint32_t write(void const *buffer, std::uint32_t length) override; - virtual osd_file::error truncate(std::uint64_t offset) override; - virtual osd_file::error flush() override; + virtual std::error_condition truncate(std::uint64_t offset) override; + virtual std::error_condition flush() override; protected: @@ -326,11 +222,7 @@ protected: private: static constexpr std::size_t FILE_BUFFER_SIZE = 512; - osd_file::error osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual); - osd_file::error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual); - osd_file::ptr m_file; // OSD file handle - zlib_data::ptr m_zdata; // compression data std::uint64_t m_bufferbase; // base offset of internal buffer std::uint32_t m_bufferbytes; // bytes currently loaded into buffer std::uint8_t m_buffer[FILE_BUFFER_SIZE]; // buffer data @@ -673,14 +565,14 @@ std::uint32_t core_in_memory_file::read(void *buffer, std::uint32_t length) truncate - truncate a file -------------------------------------------------*/ -osd_file::error core_in_memory_file::truncate(std::uint64_t offset) +std::error_condition core_in_memory_file::truncate(std::uint64_t offset) { if (m_length < offset) - return osd_file::error::FAILURE; + return std::errc::io_error; // TODO: revisit this error code // adjust to new length and offset set_length(offset); - return osd_file::error::NONE; + return std::error_condition(); } @@ -719,91 +611,6 @@ std::size_t core_in_memory_file::safe_buffer_copy( core_osd_file::~core_osd_file() { // close files and free memory - if (m_zdata) - core_osd_file::compress(FCOMPRESS_NONE); -} - - -/*------------------------------------------------- - compress - enable/disable streaming file - compression via zlib; level is 0 to disable - compression, or up to 9 for max compression --------------------------------------------------*/ - -osd_file::error core_osd_file::compress(int level) -{ - osd_file::error result = osd_file::error::NONE; - - // can only do this for read-only and write-only cases - if (read_access() && write_access()) - return osd_file::error::INVALID_ACCESS; - - // if we have been compressing, flush and free the data - if (m_zdata && (level == FCOMPRESS_NONE)) - { - int zerr = Z_OK; - - // flush any remaining data if we are writing - while (write_access() && (zerr != Z_STREAM_END)) - { - // deflate some more - zerr = m_zdata->finalise(); - if ((zerr != Z_STREAM_END) && (zerr != Z_OK)) - { - result = osd_file::error::INVALID_DATA; - break; - } - - // write the data - if (m_zdata->has_output()) - { - std::uint32_t actualdata; - auto const filerr = m_file->write(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), actualdata); - if (filerr != osd_file::error::NONE) - break; - m_zdata->add_realoffset(actualdata); - m_zdata->reset_output(); - } - } - - // free memory - m_zdata.reset(); - } - - // if we are just starting to compress, allocate a new buffer - if (!m_zdata && (level > FCOMPRESS_NONE)) - { - int zerr; - - // initialize the stream and compressor - if (write_access()) - zerr = zlib_data::start_compression(level, offset(), m_zdata); - else - zerr = zlib_data::start_decompression(offset(), m_zdata); - - // on error, return an error - if (zerr != Z_OK) - return osd_file::error::OUT_OF_MEMORY; - - // flush buffers - m_bufferbytes = 0; - } - - return result; -} - - -/*------------------------------------------------- - seek - seek within a file --------------------------------------------------*/ - -int core_osd_file::seek(std::int64_t offset, int whence) -{ - // error if compressing - if (m_zdata) - return 1; - else - return core_in_memory_file::seek(offset, whence); } @@ -833,7 +640,7 @@ std::uint32_t core_osd_file::read(void *buffer, std::uint32_t length) // read as much as makes sense into the buffer m_bufferbase = offset() + bytes_read; m_bufferbytes = 0; - osd_or_zlib_read(m_buffer, m_bufferbase, sizeof(m_buffer), m_bufferbytes); + m_file->read(m_buffer, m_bufferbase, sizeof(m_buffer), m_bufferbytes); // do a bounded copy from the buffer to the destination bytes_read += safe_buffer_copy(m_buffer, 0, m_bufferbytes, buffer, bytes_read, length); @@ -842,7 +649,7 @@ std::uint32_t core_osd_file::read(void *buffer, std::uint32_t length) { // read the remainder directly from the file std::uint32_t new_bytes_read = 0; - osd_or_zlib_read(reinterpret_cast<std::uint8_t *>(buffer) + bytes_read, offset() + bytes_read, length - bytes_read, new_bytes_read); + m_file->read(reinterpret_cast<std::uint8_t *>(buffer) + bytes_read, offset() + bytes_read, length - bytes_read, new_bytes_read); bytes_read += new_bytes_read; } } @@ -866,18 +673,16 @@ void const *core_osd_file::buffer() { // allocate some memory void *buf = allocate(); - if (!buf) return nullptr; + if (!buf) + return nullptr; // read the file std::uint32_t read_length = 0; - auto const filerr = osd_or_zlib_read(buf, 0, length(), read_length); - if ((filerr != osd_file::error::NONE) || (read_length != length())) + auto const filerr = m_file->read(buf, 0, length(), read_length); + if (filerr || (read_length != length())) purge(); else - { - // close the file because we don't need it anymore - m_file.reset(); - } + m_file.reset(); // close the file because we don't need it anymore } return core_in_memory_file::buffer(); } @@ -901,7 +706,7 @@ std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length) // do the write std::uint32_t bytes_written = 0; - osd_or_zlib_write(buffer, offset(), length, bytes_written); + m_file->write(buffer, offset(), length, bytes_written); // return the number of bytes written add_offset(bytes_written); @@ -913,19 +718,19 @@ std::uint32_t core_osd_file::write(void const *buffer, std::uint32_t length) truncate - truncate a file -------------------------------------------------*/ -osd_file::error core_osd_file::truncate(std::uint64_t offset) +std::error_condition core_osd_file::truncate(std::uint64_t offset) { if (is_loaded()) return core_in_memory_file::truncate(offset); // truncate file auto const err = m_file->truncate(offset); - if (err != osd_file::error::NONE) + if (err) return err; // and adjust to new length and offset set_length(offset); - return osd_file::error::NONE; + return std::error_condition(); } @@ -933,7 +738,7 @@ osd_file::error core_osd_file::truncate(std::uint64_t offset) flush - flush file buffers -------------------------------------------------*/ -osd_file::error core_osd_file::flush() +std::error_condition core_osd_file::flush() { if (is_loaded()) return core_in_memory_file::flush(); @@ -947,116 +752,6 @@ osd_file::error core_osd_file::flush() return m_file->flush(); } - -/*------------------------------------------------- - osd_or_zlib_read - wrapper for osd_read that - handles zlib-compressed data --------------------------------------------------*/ - -osd_file::error core_osd_file::osd_or_zlib_read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) -{ - // if no compression, just pass through - if (!m_zdata) - return m_file->read(buffer, offset, length, actual); - - // if the offset doesn't match the next offset, fail - if (!m_zdata->is_nextoffset(offset)) - return osd_file::error::INVALID_ACCESS; - - // set up the destination - osd_file::error filerr = osd_file::error::NONE; - m_zdata->set_output(buffer, length); - while (!m_zdata->output_full()) - { - // if we didn't make progress, report an error or the end - if (m_zdata->has_input()) - { - auto const zerr = m_zdata->decompress(); - if (Z_OK != zerr) - { - if (Z_STREAM_END != zerr) filerr = osd_file::error::INVALID_DATA; - break; - } - } - - // fetch more data if needed - if (!m_zdata->has_input()) - { - std::uint32_t actualdata = 0; - filerr = m_file->read(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->buffer_size(), actualdata); - if (filerr != osd_file::error::NONE) break; - m_zdata->add_realoffset(actualdata); - m_zdata->reset_input(actualdata); - if (!m_zdata->has_input()) break; - } - } - - // adjust everything - actual = length - m_zdata->output_space(); - m_zdata->add_nextoffset(actual); - return filerr; -} - - -/*------------------------------------------------- - osd_or_zlib_write - wrapper for osd_write that - handles zlib-compressed data --------------------------------------------------*/ - -/** - * @fn osd_file::error osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t actual) - * - * @brief OSD or zlib write. - * - * @param buffer The buffer. - * @param offset The offset. - * @param length The length. - * @param [in,out] actual The actual. - * - * @return A osd_file::error. - */ - -osd_file::error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) -{ - // if no compression, just pass through - if (!m_zdata) - return m_file->write(buffer, offset, length, actual); - - // if the offset doesn't match the next offset, fail - if (!m_zdata->is_nextoffset(offset)) - return osd_file::error::INVALID_ACCESS; - - // set up the source - m_zdata->set_input(buffer, length); - while (m_zdata->has_input()) - { - // if we didn't make progress, report an error or the end - auto const zerr = m_zdata->compress(); - if (zerr != Z_OK) - { - actual = length - m_zdata->input_size(); - m_zdata->add_nextoffset(actual); - return osd_file::error::INVALID_DATA; - } - - // write more data if we are full up - if (m_zdata->output_full()) - { - std::uint32_t actualdata = 0; - auto const filerr = m_file->write(m_zdata->buffer_data(), m_zdata->realoffset(), m_zdata->output_size(), actualdata); - if (filerr != osd_file::error::NONE) - return filerr; - m_zdata->add_realoffset(actualdata); - m_zdata->reset_output(); - } - } - - // we wrote everything - actual = length; - m_zdata->add_nextoffset(actual); - return osd_file::error::NONE; -} - } // anonymous namespace @@ -1070,23 +765,23 @@ osd_file::error core_osd_file::osd_or_zlib_write(void const *buffer, std::uint64 return an error code -------------------------------------------------*/ -osd_file::error core_file::open(std::string const &filename, std::uint32_t openflags, ptr &file) +std::error_condition core_file::open(std::string_view filename, std::uint32_t openflags, ptr &file) { try { // attempt to open the file osd_file::ptr f; std::uint64_t length = 0; - auto const filerr = osd_file::open(filename, openflags, f, length); - if (filerr != osd_file::error::NONE) + auto const filerr = osd_file::open(std::string(filename), openflags, f, length); // FIXME: allow osd_file to accept std::string_view + if (filerr) return filerr; file = std::make_unique<core_osd_file>(openflags, std::move(f), length); - return osd_file::error::NONE; + return std::error_condition(); } catch (...) { - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -1096,20 +791,20 @@ osd_file::error core_file::open(std::string const &filename, std::uint32_t openf like access and return an error code -------------------------------------------------*/ -osd_file::error core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) +std::error_condition core_file::open_ram(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) { // can only do this for read access if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE)) - return osd_file::error::INVALID_ACCESS; + return std::errc::invalid_argument; try { file.reset(new core_in_memory_file(openflags, data, length, false)); - return osd_file::error::NONE; + return std::error_condition(); } catch (...) { - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -1120,24 +815,24 @@ osd_file::error core_file::open_ram(void const *data, std::size_t length, std::u error code -------------------------------------------------*/ -osd_file::error core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) +std::error_condition core_file::open_ram_copy(void const *data, std::size_t length, std::uint32_t openflags, ptr &file) { // can only do this for read access if ((openflags & OPEN_FLAG_WRITE) || (openflags & OPEN_FLAG_CREATE)) - return osd_file::error::INVALID_ACCESS; + return std::errc::invalid_argument; try { ptr result(new core_in_memory_file(openflags, data, length, true)); if (!result->buffer()) - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; file = std::move(result); - return osd_file::error::NONE; + return std::error_condition(); } catch (...) { - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -1147,17 +842,14 @@ osd_file::error core_file::open_ram_copy(void const *data, std::size_t length, s object and return an error code -------------------------------------------------*/ -osd_file::error core_file::open_proxy(core_file &file, ptr &proxy) +std::error_condition core_file::open_proxy(core_file &file, ptr &proxy) { - try - { - proxy = std::make_unique<core_proxy_file>(file); - return osd_file::error::NONE; - } - catch (...) - { - return osd_file::error::OUT_OF_MEMORY; - } + ptr result(new (std::nothrow) core_proxy_file(file)); + if (!result) + return std::errc::not_enough_memory; + + proxy = std::move(result); + return std::error_condition(); } @@ -1176,61 +868,64 @@ core_file::~core_file() pointer -------------------------------------------------*/ -osd_file::error core_file::load(std::string const &filename, void **data, std::uint32_t &length) +std::error_condition core_file::load(std::string_view filename, void **data, std::uint32_t &length) { ptr file; // attempt to open the file auto const err = open(filename, OPEN_FLAG_READ, file); - if (err != osd_file::error::NONE) + if (err) return err; // get the size auto const size = file->size(); if (std::uint32_t(size) != size) - return osd_file::error::OUT_OF_MEMORY; + return std::errc::file_too_large; // allocate memory *data = malloc(size); + if (!*data) + return std::errc::not_enough_memory; length = std::uint32_t(size); // read the data if (file->read(*data, size) != size) { free(*data); - return osd_file::error::FAILURE; + return std::errc::io_error; // TODO: revisit this error code } // close the file and return data - return osd_file::error::NONE; + return std::error_condition(); } -osd_file::error core_file::load(std::string const &filename, std::vector<uint8_t> &data) +std::error_condition core_file::load(std::string_view filename, std::vector<uint8_t> &data) { ptr file; // attempt to open the file auto const err = open(filename, OPEN_FLAG_READ, file); - if (err != osd_file::error::NONE) + if (err) return err; // get the size auto const size = file->size(); if (std::uint32_t(size) != size) - return osd_file::error::OUT_OF_MEMORY; + return std::errc::file_too_large; // allocate memory - data.resize(size); + try { data.resize(size); } + catch (...) { return std::errc::not_enough_memory; } // read the data if (file->read(&data[0], size) != size) { data.clear(); - return osd_file::error::FAILURE; + return std::errc::io_error; // TODO: revisit this error code } // close the file and return data - return osd_file::error::NONE; + return std::error_condition(); } @@ -1256,7 +951,7 @@ core_file::core_file() // assumptions about path separators // ------------------------------------------------- -std::string_view core_filename_extract_base(std::string_view name, bool strip_extension) +std::string_view core_filename_extract_base(std::string_view name, bool strip_extension) noexcept { // find the start of the basename auto const start = std::find_if(name.rbegin(), name.rend(), &util::is_directory_separator); @@ -1279,7 +974,7 @@ std::string_view core_filename_extract_base(std::string_view name, bool strip_ex // core_filename_extract_extension // ------------------------------------------------- -std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period) +std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period) noexcept { auto loc = filename.find_last_of('.'); if (loc != std::string_view::npos) @@ -1294,7 +989,7 @@ std::string_view core_filename_extract_extension(std::string_view filename, bool // filename end with the specified extension? // ------------------------------------------------- -bool core_filename_ends_with(std::string_view filename, std::string_view extension) +bool core_filename_ends_with(std::string_view filename, std::string_view extension) noexcept { auto namelen = filename.length(); auto extlen = extension.length(); diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h index 6aaa8f609e1..19febbb46f1 100644 --- a/src/lib/util/corefile.h +++ b/src/lib/util/corefile.h @@ -12,14 +12,13 @@ #pragma once - #include "osdfile.h" #include "strformat.h" #include <cstdint> #include <memory> -#include <string> #include <string_view> +#include <system_error> namespace util { @@ -30,11 +29,6 @@ namespace util { #define OPEN_FLAG_NO_BOM 0x0100 /* don't output BOM */ -#define FCOMPRESS_NONE 0 /* no compression */ -#define FCOMPRESS_MIN 1 /* minimal compression */ -#define FCOMPRESS_MEDIUM 6 /* standard compression */ -#define FCOMPRESS_MAX 9 /* maximum compression */ - /*************************************************************************** TYPE DEFINITIONS @@ -49,23 +43,20 @@ public: // ----- file open/close ----- // open a file with the specified filename - static osd_file::error open(std::string const &filename, std::uint32_t openflags, ptr &file); + static std::error_condition open(std::string_view filename, std::uint32_t openflags, ptr &file); // open a RAM-based "file" using the given data and length (read-only) - static osd_file::error open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file); + static std::error_condition open_ram(const void *data, std::size_t length, std::uint32_t openflags, ptr &file); // open a RAM-based "file" using the given data and length (read-only), copying the data - static osd_file::error open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file); + static std::error_condition open_ram_copy(const void *data, std::size_t length, std::uint32_t openflags, ptr &file); // open a proxy "file" that forwards requests to another file object - static osd_file::error open_proxy(core_file &file, ptr &proxy); + static std::error_condition open_proxy(core_file &file, ptr &proxy); // close an open file virtual ~core_file(); - // enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression - virtual osd_file::error compress(int level) = 0; - // ----- file positioning ----- @@ -101,8 +92,8 @@ public: virtual const void *buffer() = 0; // open a file with the specified filename, read it into memory, and return a pointer - static osd_file::error load(std::string const &filename, void **data, std::uint32_t &length); - static osd_file::error load(std::string const &filename, std::vector<uint8_t> &data); + static std::error_condition load(std::string_view filename, void **data, std::uint32_t &length); + static std::error_condition load(std::string_view filename, std::vector<uint8_t> &data); // ----- file write ----- @@ -121,32 +112,16 @@ public: } // file truncation - virtual osd_file::error truncate(std::uint64_t offset) = 0; + virtual std::error_condition truncate(std::uint64_t offset) = 0; // flush file buffers - virtual osd_file::error flush() = 0; + virtual std::error_condition flush() = 0; protected: core_file(); }; - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -// is a given character a directory separator? - -constexpr bool is_directory_separator(char c) -{ -#if defined(WIN32) - return ('\\' == c) || ('/' == c) || (':' == c); -#else - return '/' == c; -#endif -} - } // namespace util @@ -157,13 +132,13 @@ constexpr bool is_directory_separator(char c) /* ----- filename utilities ----- */ // extract the base part of a filename (remove extensions and paths) -std::string_view core_filename_extract_base(std::string_view name, bool strip_extension = false); +std::string_view core_filename_extract_base(std::string_view name, bool strip_extension = false) noexcept; // extracts the file extension from a filename -std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period = false); +std::string_view core_filename_extract_extension(std::string_view filename, bool strip_period = false) noexcept; // true if the given filename ends with a particular extension -bool core_filename_ends_with(std::string_view filename, std::string_view extension); +bool core_filename_ends_with(std::string_view filename, std::string_view extension) noexcept; #endif // MAME_LIB_UTIL_COREFILE_H diff --git a/src/lib/util/harddisk.cpp b/src/lib/util/harddisk.cpp index e91759c44f2..2e8d14f9a8a 100644 --- a/src/lib/util/harddisk.cpp +++ b/src/lib/util/harddisk.cpp @@ -8,11 +8,13 @@ ***************************************************************************/ -#include <cassert> #include "harddisk.h" -#include "osdcore.h" + +#include "corefile.h" + #include <cstdlib> + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -40,7 +42,7 @@ hard_disk_file *hard_disk_open(chd_file *chd) int cylinders, heads, sectors, sectorbytes; hard_disk_file *file; std::string metadata; - chd_error err; + std::error_condition err; /* punt if no CHD */ if (chd == nullptr) @@ -48,7 +50,7 @@ hard_disk_file *hard_disk_open(chd_file *chd) /* read the hard disk metadata */ err = chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata); - if (err != CHDERR_NONE) + if (err) return nullptr; /* parse the metadata */ @@ -177,8 +179,8 @@ uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer) { if (file->chd) { - chd_error err = file->chd->read_units(lbasector, buffer); - return (err == CHDERR_NONE); + std::error_condition err = file->chd->read_units(lbasector, buffer); + return !err; } else { @@ -211,8 +213,8 @@ uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *b { if (file->chd) { - chd_error err = file->chd->write_units(lbasector, buffer); - return (err == CHDERR_NONE); + std::error_condition err = file->chd->write_units(lbasector, buffer); + return !err; } else { diff --git a/src/lib/util/harddisk.h b/src/lib/util/harddisk.h index 2a4b727e7e7..e6fae165f19 100644 --- a/src/lib/util/harddisk.h +++ b/src/lib/util/harddisk.h @@ -8,13 +8,15 @@ ***************************************************************************/ -#ifndef MAME_UTIL_HARDDISK_H -#define MAME_UTIL_HARDDISK_H +#ifndef MAME_LIB_UTIL_HARDDISK_H +#define MAME_LIB_UTIL_HARDDISK_H #pragma once -#include "osdcore.h" #include "chd.h" +#include "utilfwd.h" + +#include "osdcore.h" /*************************************************************************** @@ -49,4 +51,4 @@ hard_disk_info *hard_disk_get_info(hard_disk_file *file); uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer); uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer); -#endif // MAME_UTIL_HARDDISK_H +#endif // MAME_LIB_UTIL_HARDDISK_H diff --git a/src/lib/util/ioprocs.cpp b/src/lib/util/ioprocs.cpp new file mode 100644 index 00000000000..1f52a3daf97 --- /dev/null +++ b/src/lib/util/ioprocs.cpp @@ -0,0 +1,1248 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocs.h + + I/O interfaces + +***************************************************************************/ + +#include "ioprocs.h" + +#include "corefile.h" +#include "ioprocsfill.h" + +#include "osdfile.h" + +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstring> +#include <iterator> +#include <limits> +#include <type_traits> + + +namespace util { + +namespace { + +// helper for holding a block of memory and deallocating it (or not) as necessary + +template <typename T, bool Owned> +class ram_adapter_base : public virtual random_access +{ +public: + virtual ~ram_adapter_base() + { + if constexpr (Owned) + std::free(m_data); + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + switch (whence) + { + case SEEK_SET: + if (0 > offset) + return std::errc::invalid_argument; + m_pointer = std::uint64_t(offset); + return std::error_condition(); + + case SEEK_CUR: + if (0 > offset) + { + if (std::uint64_t(-offset) > m_pointer) + return std::errc::invalid_argument; + } + else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer) + { + return std::errc::invalid_argument; + } + m_pointer += offset; + return std::error_condition(); + + case SEEK_END: + if (0 > offset) + { + if (std::uint64_t(-offset) > m_size) + return std::errc::invalid_argument; + } + else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_size) + { + return std::errc::invalid_argument; + } + m_pointer = std::uint64_t(m_size) + offset; + return std::error_condition(); + + default: + return std::errc::invalid_argument; + } + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + result = m_pointer; + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + if (std::numeric_limits<uint64_t>::max() < m_size) + return std::errc::file_too_large; + + result = m_size; + return std::error_condition(); + } + +protected: + template <typename U> + ram_adapter_base(U *data, std::size_t size) noexcept : m_data(reinterpret_cast<T>(data)), m_size(size) + { + static_assert(sizeof(*m_data) == 1U, "Element type must be byte-sized"); + assert(m_data || !m_size); + } + + T m_data; + std::uint64_t m_pointer = 0U; + std::size_t m_size; +}; + + +// RAM read implementation + +template <typename T, bool Owned> +class ram_read_adapter : public ram_adapter_base<T, Owned>, public virtual random_read +{ +public: + template <typename U> + ram_read_adapter(U *data, std::size_t size) noexcept : ram_adapter_base<T, Owned>(data, size) + { + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + do_read(this->m_pointer, buffer, length, actual); + this->m_pointer += actual; + return std::error_condition(); + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + do_read(offset, buffer, length, actual); + return std::error_condition(); + } + +private: + void do_read(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) const noexcept + { + if ((offset < this->m_size) && length) + { + actual = std::min(std::size_t(this->m_size - offset), length); + if constexpr (Owned) + std::memcpy(buffer, this->m_data + offset, actual); + else + std::memmove(buffer, this->m_data + offset, actual); + } + else + { + actual = 0U; + } + } +}; + + +// helper for holding a stdio FILE and closing it (or not) as necessary + +class stdio_adapter_base : public virtual random_access +{ +public: + virtual ~stdio_adapter_base() + { + if (m_close) + std::fclose(m_file); + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + if ((std::numeric_limits<long>::max() < offset) || (std::numeric_limits<long>::min() > offset)) + return std::errc::invalid_argument; + else if (!std::fseek(m_file, long(offset), whence)) + return std::error_condition(); + else + return std::error_condition(errno, std::generic_category()); + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + long const pos = std::ftell(m_file); + if (0 > pos) + return std::error_condition(errno, std::generic_category()); + result = static_cast<unsigned long>(pos); + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + std::fpos_t oldpos; + if (std::fgetpos(m_file, &oldpos)) + return std::error_condition(errno, std::generic_category()); + + long endpos = -1; + if (!std::fseek(m_file, 0, SEEK_END)) + { + m_dangling_read = m_dangling_write = false; + endpos = std::ftell(m_file); + } + std::error_condition err; + if (0 > endpos) + err.assign(errno, std::generic_category()); + else if (std::numeric_limits<std::uint64_t>::max() < static_cast<unsigned long>(endpos)) + err = std::errc::file_too_large; + else + result = static_cast<unsigned long>(endpos); + + if (!std::fsetpos(m_file, &oldpos)) + m_dangling_read = m_dangling_write = false; + else if (!err) + err.assign(errno, std::generic_category()); + + return err; + } + +protected: + stdio_adapter_base(FILE *file, bool close) noexcept : m_file(file), m_close(close) + { + assert(m_file); + } + + FILE *file() noexcept + { + return m_file; + } + +private: + FILE *const m_file; + bool const m_close; + +protected: + bool m_dangling_read = true, m_dangling_write = true; +}; + + +// stdio read implementation + +class stdio_read_adapter : public stdio_adapter_base, public virtual random_read +{ +public: + stdio_read_adapter(FILE *file, bool close) noexcept : stdio_adapter_base(file, close) + { + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + if (m_dangling_write) + { + if (std::fflush(file())) + { + std::clearerr(file()); + actual = 0U; + return std::error_condition(errno, std::generic_category()); + } + m_dangling_write = false; + } + + actual = std::fread(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_read = true; + if (length != actual) + { + if (std::ferror(file())) + { + std::clearerr(file()); + return std::error_condition(errno, std::generic_category()); + } + else if (std::feof(file())) + { + m_dangling_read = false; + } + } + + return std::error_condition(); + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset) + return std::errc::invalid_argument; + + std::fpos_t oldpos; + if (std::fgetpos(file(), &oldpos)) + return std::error_condition(errno, std::generic_category()); + + std::error_condition err; + if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET)) + { + err.assign(errno, std::generic_category()); + } + else + { + m_dangling_write = false; + actual = std::fread(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_read = true; + if (length != actual) + { + if (std::ferror(file())) + { + err.assign(errno, std::generic_category()); + std::clearerr(file()); + } + else if (std::feof(file())) + { + m_dangling_read = false; + } + } + } + + if (!std::fsetpos(file(), &oldpos)) + m_dangling_read = m_dangling_write = false; + else if (!err) + err.assign(errno, std::generic_category()); + + return err; + } +}; + + +// stdio read/write implementation + +class stdio_read_write_adapter : public stdio_read_adapter, public random_read_write +{ +public: + using stdio_read_adapter::stdio_read_adapter; + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + if (std::fflush(file())) + { + std::clearerr(file()); + return std::error_condition(errno, std::generic_category()); + } + m_dangling_write = false; + return std::error_condition(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + if (m_dangling_read) + { + if (std::fseek(file(), 0, SEEK_CUR)) + { + actual = 0U; + return std::error_condition(errno, std::generic_category()); + } + m_dangling_read = false; + } + + actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_write = true; + if (length != actual) + { + std::clearerr(file()); + return std::error_condition(errno, std::generic_category()); + } + + return std::error_condition(); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset) + return std::errc::invalid_argument; + + std::fpos_t oldpos; + if (std::fgetpos(file(), &oldpos)) + return std::error_condition(errno, std::generic_category()); + + std::error_condition err; + if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET)) + { + err.assign(errno, std::generic_category()); + } + else + { + m_dangling_read = false; + actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_write = true; + if (length != actual) + { + err.assign(errno, std::generic_category()); + std::clearerr(file()); + } + } + + if (!std::fsetpos(file(), &oldpos)) + m_dangling_read = m_dangling_write = false; + else if (!err) + err.assign(errno, std::generic_category()); + + return err; + } +}; + + +// stdio helper that fills space when writing past the end-of-file + +class stdio_read_write_filler : public random_read_fill_wrapper<stdio_read_write_adapter> +{ +public: + stdio_read_write_filler(FILE *file, bool close, std::uint8_t fill) noexcept : random_read_fill_wrapper<stdio_read_write_adapter>(file, close) + { + set_filler(fill); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + long const offset = std::ftell(file()); + if (0 > offset) + return std::error_condition(errno, std::generic_category()); + + if (std::fseek(file(), 0, SEEK_END)) + { + std::error_condition err(errno, std::generic_category()); + if (!std::fseek(file(), offset, SEEK_SET)) + m_dangling_read = m_dangling_write = false; + return err; + } + m_dangling_read = m_dangling_write = false; + long endpos = std::ftell(file()); + if (0 > endpos) + { + std::error_condition err(errno, std::generic_category()); + std::fseek(file(), offset, SEEK_SET); + return err; + } + + if (offset > endpos) + { + std::uint8_t block[1024]; + std::fill_n( + block, + std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos), + get_filler()); + do + { + std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos); + std::size_t const filled = std::fwrite(block, sizeof(block[0]), chunk, file()); + endpos += filled; + m_dangling_write = true; + if (chunk != filled) + { + std::error_condition err(errno, std::generic_category()); + std::clearerr(file()); + if (!std::fseek(file(), offset, SEEK_SET)) + m_dangling_write = false; + return err; + } + } + while (static_cast<unsigned long>(endpos) < offset); + } + else if ((offset < endpos) && std::fseek(file(), offset, SEEK_SET)) + { + return std::error_condition(errno, std::generic_category()); + } + + actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_write = true; + if (length != actual) + { + std::clearerr(file()); + return std::error_condition(errno, std::generic_category()); + } + + return std::error_condition(); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + if (static_cast<unsigned long>(std::numeric_limits<long>::max()) < offset) + return std::errc::invalid_argument; + + std::fpos_t oldpos; + if (std::fgetpos(file(), &oldpos)) + return std::error_condition(errno, std::generic_category()); + + std::error_condition err; + if (std::fseek(file(), 0, SEEK_END)) + { + err.assign(errno, std::generic_category()); + } + else + { + m_dangling_read = m_dangling_write = false; + long endpos = std::ftell(file()); + if (0 > endpos) + { + err.assign(errno, std::generic_category()); + } + else if (static_cast<unsigned long>(endpos) > offset) + { + if (std::fseek(file(), long(static_cast<unsigned long>(offset)), SEEK_SET)) + err.assign(errno, std::generic_category()); + } + else if (static_cast<unsigned long>(endpos) < offset) + { + std::uint8_t block[1024]; + std::fill_n( + block, + std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos), + get_filler()); + do + { + std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t, long> >(std::size(block), offset - endpos); + std::size_t const filled = std::fwrite(block, sizeof(block[0]), chunk, file()); + endpos += filled; + m_dangling_write = true; + if (chunk != filled) + { + err.assign(errno, std::generic_category()); + std::clearerr(file()); + } + } + while (!err && (static_cast<unsigned long>(endpos) < offset)); + } + } + + if (!err) + { + actual = std::fwrite(buffer, sizeof(std::uint8_t), length, file()); + m_dangling_write = true; + if (length != actual) + { + err.assign(errno, std::generic_category()); + std::clearerr(file()); + } + } + + if (!std::fsetpos(file(), &oldpos)) + m_dangling_read = m_dangling_write = false; + else if (!err) + err.assign(errno, std::generic_category()); + + return err; + } +}; + + +// helper class for holding an osd_file and closing it (or not) as necessary + +class osd_file_adapter_base : public virtual random_access +{ +public: + virtual ~osd_file_adapter_base() + { + if (m_close) + delete m_file; + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + switch (whence) + { + case SEEK_SET: + if (0 > offset) + return std::errc::invalid_argument; + m_pointer = std::uint64_t(offset); + return std::error_condition(); + + case SEEK_CUR: + if (0 > offset) + { + if (std::uint64_t(-offset) > m_pointer) + return std::errc::invalid_argument; + } + else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer) + { + return std::errc::invalid_argument; + } + m_pointer += offset; + return std::error_condition(); + + // TODO: add SEEK_END when osd_file can support it - should it return a different error? + default: + return std::errc::invalid_argument; + } + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + result = m_pointer; + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + // not supported by osd_file + return std::errc::not_supported; // TODO: revisit this error code + } + +protected: + osd_file_adapter_base(osd_file::ptr &&file) noexcept : m_file(file.release()), m_close(true) + { + assert(m_file); + } + + osd_file_adapter_base(osd_file &file) noexcept : m_file(&file), m_close(false) + { + } + + osd_file &file() noexcept + { + return *m_file; + } + + std::uint64_t m_pointer = 0U; + +private: + osd_file *const m_file; + bool const m_close; +}; + + +// osd_file read implementation + +class osd_file_read_adapter : public osd_file_adapter_base, public virtual random_read +{ +public: + osd_file_read_adapter(osd_file::ptr &&file) noexcept : osd_file_adapter_base(std::move(file)) + { + } + + osd_file_read_adapter(osd_file &file) noexcept : osd_file_adapter_base(file) + { + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? + if (std::numeric_limits<std::uint32_t>::max() < length) + { + actual = 0U; + return std::errc::invalid_argument; + } + + // actual length not valid on error + std::uint32_t count; + std::error_condition err = file().read(buffer, m_pointer, std::uint32_t(length), count); + if (!err) + { + m_pointer += count; + actual = std::size_t(count); + } + else + { + actual = 0U; + } + return err; + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? + if (std::numeric_limits<std::uint32_t>::max() < length) + { + actual = 0U; + return std::errc::invalid_argument; + } + + // actual length not valid on error + std::uint32_t count; + std::error_condition err = file().read(buffer, offset, std::uint32_t(length), count); + if (!err) + actual = std::size_t(count); + else + actual = 0U; + return err; + } +}; + + +// osd_file read/write implementation + +class osd_file_read_write_adapter : public osd_file_read_adapter, public random_read_write +{ +public: + using osd_file_read_adapter::osd_file_read_adapter; + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + return file().flush(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + while (length) + { + // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t written; + std::error_condition err = file().write(buffer, m_pointer, chunk, written); + if (err) + return err; + m_pointer += written; + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + actual += written; + } + return std::error_condition(); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + while (length) + { + // actual length not valid on error + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t written; + std::error_condition err = file().write(buffer, offset, chunk, written); + if (err) + return err; + offset += written; + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + actual += written; + } + return std::error_condition(); + } +}; + + +// helper class for holding a core_file and closing it (or not) as necessary + +class core_file_adapter_base : public virtual random_access +{ +public: + virtual ~core_file_adapter_base() + { + if (m_close) + delete m_file; + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + if (!m_file->seek(offset, whence)) + return std::error_condition(); + else + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + // no error reporting + result = m_file->tell(); + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + // no error reporting + result = m_file->size(); + return std::error_condition(); + } + +protected: + core_file_adapter_base(core_file::ptr &&file) noexcept : m_file(file.release()), m_close(true) + { + assert(m_file); + } + + core_file_adapter_base(core_file &file) noexcept : m_file(&file), m_close(false) + { + } + + core_file &file() noexcept + { + return *m_file; + } + +private: + core_file *const m_file; + bool const m_close; +}; + + +// core_file read implementation + +class core_file_read_adapter : public core_file_adapter_base, public virtual random_read +{ +public: + core_file_read_adapter(core_file::ptr &&file) noexcept : core_file_adapter_base(std::move(file)) + { + } + + core_file_read_adapter(core_file &file) noexcept : core_file_adapter_base(file) + { + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? + if (std::numeric_limits<std::uint32_t>::max() < length) + { + actual = 0U; + return std::errc::invalid_argument; + } + + // no way to distinguish between EOF and error + actual = file().read(buffer, std::uint32_t(length)); + return std::error_condition(); + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + // TODO: should the client have to deal with reading less than expected even if EOF isn't hit? + if (std::numeric_limits<std::uint32_t>::max() < length) + return std::errc::invalid_argument; + + // no error reporting for tell + std::uint64_t const oldpos = file().tell(); + if (file().seek(offset, SEEK_SET)) + { + file().seek(oldpos, SEEK_SET); + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } + + // no way to distinguish between EOF and error + actual = file().read(buffer, std::uint32_t(length)); + + if (!file().seek(oldpos, SEEK_SET)) + return std::error_condition(); + else + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } +}; + + +// core_file read/write implementation + +class core_file_read_write_adapter : public core_file_read_adapter, public random_read_write +{ +public: + using core_file_read_adapter::core_file_read_adapter; + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + return file().flush(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + while (length) + { + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t const written = file().write(buffer, chunk); + actual += written; + if (written < chunk) + return std::errc::io_error; // TODO: better error reporting for core_file + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + return std::error_condition(); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + // no error reporting for tell + std::uint64_t const oldpos = file().tell(); + if (file().seek(offset, SEEK_SET)) + { + file().seek(oldpos, SEEK_SET); + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } + + std::error_condition err; + while (!err && length) + { + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t const written = file().write(buffer, chunk); + actual += written; + if (written < chunk) + { + err = std::errc::io_error; // TODO: better error reporting for core_file + } + else + { + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + } + + if (!file().seek(oldpos, SEEK_SET) || err) + return err; + else + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } +}; + + +// core_file helper that fills space when writing past the end-of-file + +class core_file_read_write_filler : public random_read_fill_wrapper<core_file_read_write_adapter> +{ +public: + core_file_read_write_filler(core_file::ptr &&file, std::uint8_t fill) noexcept : random_read_fill_wrapper<core_file_read_write_adapter>(std::move(file)) + { + set_filler(fill); + } + + core_file_read_write_filler(core_file &file, std::uint8_t fill) noexcept : random_read_fill_wrapper<core_file_read_write_adapter>(file) + { + set_filler(fill); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + // no error reporting for tell or size + std::uint64_t const offset = file().tell(); + std::uint64_t endpos = file().size(); + if (endpos < offset) + { + if (file().seek(endpos, SEEK_SET)) + { + file().seek(offset, SEEK_SET); + actual = 0U; + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } + std::uint8_t block[1024]; + std::fill_n( + block, + std::min<std::common_type_t<std::size_t, std::uint64_t> >(std::size(block), offset - endpos), + get_filler()); + do + { + std::uint32_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(sizeof(block), offset - endpos); + std::uint32_t const filled = file().write(block, chunk); + endpos += filled; + if (chunk != filled) + { + file().seek(offset, SEEK_SET); + actual = 0U; + return std::errc::io_error; // TODO: better error reporting for core_file + } + } + while (endpos < offset); + } + + return core_file_read_write_adapter::write(buffer, length, actual); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + actual = 0U; + + // no error reporting for tell + std::uint64_t const oldpos = file().tell(); + if (file().seek(0, SEEK_END)) + { + file().seek(oldpos, SEEK_SET); + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } + std::uint64_t endpos = file().tell(); + + std::error_condition err; + if (endpos > offset) + { + if (file().seek(offset, SEEK_SET)) + err = std::errc::invalid_argument; // TODO: better error reporting for core_file + } + else if (endpos < offset) + { + std::uint8_t block[1024]; + std::fill_n( + block, + std::min<std::common_type_t<std::size_t, std::uint64_t> >(std::size(block), offset - endpos), + get_filler()); + do + { + std::uint32_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(sizeof(block), offset - endpos); + std::uint32_t const filled = file().write(block, chunk); + endpos += filled; + if (chunk != filled) + err = std::errc::io_error; // TODO: better error reporting for core_file + } + while (!err && (endpos < offset)); + } + + while (!err && length) + { + std::uint32_t const chunk = std::min<std::common_type_t<std::uint32_t, std::size_t> >(std::numeric_limits<std::uint32_t>::max(), length); + std::uint32_t const written = file().write(buffer, chunk); + actual += written; + if (written < chunk) + { + err = std::errc::io_error; // TODO: better error reporting for core_file + } + else + { + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + } + + if (!file().seek(oldpos, SEEK_SET) || err) + return err; + else + return std::errc::invalid_argument; // TODO: better error reporting for core_file + } +}; + +} // anonymous namespace + + +// creating RAM read adapters + +random_read::ptr ram_read(void const *data, std::size_t size) noexcept +{ + random_read::ptr result; + if (data || !size) + result.reset(new (std::nothrow) ram_read_adapter<std::uint8_t const *const, false>(data, size)); + return result; +} + +random_read::ptr ram_read(void const *data, std::size_t size, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<ram_read_adapter<std::uint8_t const *const, false> > > result; + if (data || !size) + result.reset(new (std::nothrow) decltype(result)::element_type(data, size)); + if (result) + result->set_filler(filler); + return result; +} + +random_read::ptr ram_read_copy(void const *data, std::size_t size) noexcept +{ + random_read::ptr result; + void *const copy = size ? std::malloc(size) : nullptr; + if (copy) + std::memcpy(copy, data, size); + if (copy || !size) + result.reset(new (std::nothrow) ram_read_adapter<std::uint8_t *const, true>(copy, size)); + if (!result) + std::free(copy); + return result; +} + +random_read::ptr ram_read_copy(void const *data, std::size_t size, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<ram_read_adapter<std::uint8_t *const, true> > > result; + void *const copy = size ? std::malloc(size) : nullptr; + if (copy) + std::memcpy(copy, data, size); + if (copy || !size) + result.reset(new (std::nothrow) decltype(result)::element_type(copy, size)); + if (!result) + std::free(copy); + return result; +} + + +// creating stdio read adapters + +random_read::ptr stdio_read(FILE *file) noexcept +{ + random_read::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_adapter(file, true)); + return result; +} + +random_read::ptr stdio_read(FILE *file, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<stdio_read_adapter> > result; + if (file) + result.reset(new (std::nothrow) decltype(result)::element_type(file, true)); + if (result) + result->set_filler(filler); + return result; +} + +random_read::ptr stdio_read_noclose(FILE *file) noexcept +{ + random_read::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_adapter(file, false)); + return result; +} + +random_read::ptr stdio_read_noclose(FILE *file, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<stdio_read_adapter> > result; + if (file) + result.reset(new (std::nothrow) decltype(result)::element_type(file, false)); + if (result) + result->set_filler(filler); + return result; +} + + +// creating stdio read/write adapters + +random_read_write::ptr stdio_read_write(FILE *file) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_write_adapter(file, true)); + return result; +} + +random_read_write::ptr stdio_read_write(FILE *file, std::uint8_t filler) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_write_filler(file, true, filler)); + return result; +} + +random_read_write::ptr stdio_read_write_noclose(FILE *file) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_write_adapter(file, false)); + return result; +} + +random_read_write::ptr stdio_read_write_noclose(FILE *file, std::uint8_t filler) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) stdio_read_write_filler(file, false, filler)); + return result; +} + + +// creating osd_file read adapters + +random_read::ptr osd_file_read(osd_file::ptr &&file) noexcept +{ + random_read::ptr result; + if (file) + result.reset(new (std::nothrow) osd_file_read_adapter(std::move(file))); + return result; +} + +random_read::ptr osd_file_read(osd_file &file) noexcept +{ + return random_read::ptr(new (std::nothrow) osd_file_read_adapter(file)); +} + + +// creating osd_file read/write adapters + +random_read_write::ptr osd_file_read_write(osd_file::ptr &&file) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) osd_file_read_write_adapter(std::move(file))); + return result; +} + +random_read_write::ptr osd_file_read_write(osd_file &file) noexcept +{ + return random_read_write::ptr(new (std::nothrow) osd_file_read_write_adapter(file)); +} + + +// creating core_file read adapters + +random_read::ptr core_file_read(core_file::ptr &&file) noexcept +{ + random_read::ptr result; + if (file) + result.reset(new (std::nothrow) core_file_read_adapter(std::move(file))); + return result; +} + +random_read::ptr core_file_read(core_file::ptr &&file, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<core_file_read_adapter> > result; + if (file) + result.reset(new (std::nothrow) decltype(result)::element_type(std::move(file))); + if (result) + result->set_filler(filler); + return result; +} + +random_read::ptr core_file_read(core_file &file) noexcept +{ + return random_read::ptr(new (std::nothrow) core_file_read_adapter(file)); +} + +random_read::ptr core_file_read(core_file &file, std::uint8_t filler) noexcept +{ + std::unique_ptr<random_read_fill_wrapper<core_file_read_adapter> > result; + result.reset(new (std::nothrow) decltype(result)::element_type(file)); + if (result) + result->set_filler(filler); + return result; +} + + +// creating core_file read/write adapters + +random_read_write::ptr core_file_read_write(core_file::ptr &&file) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) core_file_read_write_adapter(std::move(file))); + return result; +} + +random_read_write::ptr core_file_read_write(core_file::ptr &&file, std::uint8_t filler) noexcept +{ + random_read_write::ptr result; + if (file) + result.reset(new (std::nothrow) core_file_read_write_filler(std::move(file), filler)); + return result; +} + +random_read_write::ptr core_file_read_write(core_file &file) noexcept +{ + return random_read_write::ptr(new (std::nothrow) core_file_read_write_adapter(file)); +} + +random_read_write::ptr core_file_read_write(core_file &file, std::uint8_t filler) noexcept +{ + return random_read_write::ptr(new (std::nothrow) core_file_read_write_filler(file, filler)); +} + +} // namespace util diff --git a/src/lib/util/ioprocs.h b/src/lib/util/ioprocs.h new file mode 100644 index 00000000000..78c06e71318 --- /dev/null +++ b/src/lib/util/ioprocs.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocs.h + + I/O interfaces + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_IOPROCS_H +#define MAME_LIB_UTIL_IOPROCS_H + +#pragma once + +#include "utilfwd.h" + +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <memory> +#include <system_error> + + +// FIXME: make a proper place for OSD forward declarations +class osd_file; + + +namespace util { + +class read_stream +{ +public: + using ptr = std::unique_ptr<read_stream>; + + virtual ~read_stream() = default; + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; +}; + + +class write_stream +{ +public: + using ptr = std::unique_ptr<write_stream>; + + virtual ~write_stream() = default; + + virtual std::error_condition finalize() noexcept = 0; + virtual std::error_condition flush() noexcept = 0; + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; +}; + + +class read_write_stream : public virtual read_stream, public virtual write_stream +{ +public: + using ptr = std::unique_ptr<read_write_stream>; +}; + + +class random_access +{ +public: + virtual ~random_access() = default; + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept = 0; + virtual std::error_condition tell(std::uint64_t &result) noexcept = 0; + virtual std::error_condition length(std::uint64_t &result) noexcept = 0; +}; + + +class random_read : public virtual read_stream, public virtual random_access +{ +public: + using ptr = std::unique_ptr<random_read>; + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; +}; + + +class random_write : public virtual write_stream, public virtual random_access +{ +public: + using ptr = std::unique_ptr<random_write>; + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; +}; + + +class random_read_write : public read_write_stream, public virtual random_read, public virtual random_write +{ +public: + using ptr = std::unique_ptr<random_read_write>; +}; + + +random_read::ptr ram_read(void const *data, std::size_t size) noexcept; +random_read::ptr ram_read(void const *data, std::size_t size, std::uint8_t filler) noexcept; +random_read::ptr ram_read_copy(void const *data, std::size_t size) noexcept; +random_read::ptr ram_read_copy(void const *data, std::size_t size, std::uint8_t filler) noexcept; + +random_read::ptr stdio_read(FILE *file) noexcept; +random_read::ptr stdio_read(FILE *file, std::uint8_t filler) noexcept; +random_read::ptr stdio_read_noclose(FILE *file) noexcept; +random_read::ptr stdio_read_noclose(FILE *file, std::uint8_t filler) noexcept; + +random_read_write::ptr stdio_read_write(FILE *file) noexcept; +random_read_write::ptr stdio_read_write(FILE *file, std::uint8_t filler) noexcept; +random_read_write::ptr stdio_read_write_noclose(FILE *file) noexcept; +random_read_write::ptr stdio_read_write_noclose(FILE *file, std::uint8_t filler) noexcept; + +random_read::ptr osd_file_read(std::unique_ptr<osd_file> &&file) noexcept; +random_read::ptr osd_file_read(osd_file &file) noexcept; + +random_read_write::ptr osd_file_read_write(std::unique_ptr<osd_file> &&file) noexcept; +random_read_write::ptr osd_file_read_write(osd_file &file) noexcept; + +random_read::ptr core_file_read(std::unique_ptr<core_file> &&file) noexcept; +random_read::ptr core_file_read(std::unique_ptr<core_file> &&file, std::uint8_t filler) noexcept; +random_read::ptr core_file_read(core_file &file) noexcept; +random_read::ptr core_file_read(core_file &file, std::uint8_t filler) noexcept; + +random_read_write::ptr core_file_read_write(std::unique_ptr<core_file> &&file) noexcept; +random_read_write::ptr core_file_read_write(std::unique_ptr<core_file> &&file, std::uint8_t filler) noexcept; +random_read_write::ptr core_file_read_write(core_file &file) noexcept; +random_read_write::ptr core_file_read_write(core_file &file, std::uint8_t filler) noexcept; + +} // namespace util + +#endif // MAME_LIB_UTIL_IOPROCS_H diff --git a/src/lib/util/ioprocsfill.h b/src/lib/util/ioprocsfill.h new file mode 100644 index 00000000000..e49b10687f0 --- /dev/null +++ b/src/lib/util/ioprocsfill.h @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocsfill.h + + Wrappers that automatically fill extra space + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_IOPROCSFILL_H +#define MAME_LIB_UTIL_IOPROCSFILL_H + +#pragma once + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <system_error> + + +namespace util { + +template <std::uint8_t DefaultFiller> +class fill_wrapper_base +{ +public: + std::uint8_t get_filler() const noexcept + { + return m_filler; + } + + void set_filler(std::uint8_t filler) noexcept + { + m_filler = filler; + } + +private: + std::uint8_t m_filler = DefaultFiller; +}; + + +template <typename Base, std::uint8_t DefaultFiller = 0U> +class read_stream_fill_wrapper : public Base, public virtual fill_wrapper_base<DefaultFiller> +{ +public: + using Base::Base; + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err = Base::read(buffer, length, actual); + assert(length >= actual); + std::fill( + reinterpret_cast<std::uint8_t *>(buffer) + actual, + reinterpret_cast<std::uint8_t *>(buffer) + length, + fill_wrapper_base<DefaultFiller>::get_filler()); + return err; + } +}; + + +template <typename Base, std::uint8_t DefaultFiller = 0U> +class random_read_fill_wrapper : public read_stream_fill_wrapper<Base, DefaultFiller> +{ +public: + using read_stream_fill_wrapper<Base, DefaultFiller>::read_stream_fill_wrapper; + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err = Base::read_at(offset, buffer, length, actual); + assert(length >= actual); + std::fill( + reinterpret_cast<std::uint8_t *>(buffer) + actual, + reinterpret_cast<std::uint8_t *>(buffer) + length, + fill_wrapper_base<DefaultFiller>::get_filler()); + return err; + } +}; + + +template <typename Base, std::uint8_t DefaultFiller = 0U, std::size_t FillBlock = 1024U> +class random_write_fill_wrapper : public Base, public virtual fill_wrapper_base<DefaultFiller> +{ +public: + using Base::Base; + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err; + actual = 0U; + + std::uint64_t offset; + std::uint64_t current; + err = Base::tell(offset); + if (err) + return err; + err = Base::length(current); + if (err) + return err; + + if (current < offset) + { + std::uint64_t unfilled = offset - current; + std::uint8_t fill_buffer[FillBlock]; + std::fill( + fill_buffer, + fill_buffer + std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled), + fill_wrapper_base<DefaultFiller>::get_filler()); + do + { + std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled); + err = Base::write_at(current, fill_buffer, chunk, actual); + if (err) + { + actual = 0U; + return err; + } + current += chunk; + unfilled -= chunk; + } + while (unfilled); + } + + return Base::write(buffer, length, actual); + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err; + std::uint64_t current; + err = Base::length(current); + if (!err && (current < offset)) + { + std::uint64_t unfilled = offset - current; + std::uint8_t fill_buffer[FillBlock]; + std::fill( + fill_buffer, + fill_buffer + std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled), + fill_wrapper_base<DefaultFiller>::get_filler()); + do + { + std::size_t const chunk = std::min<std::common_type_t<std::size_t, std::uint64_t> >(FillBlock, unfilled); + err = Base::write_at(current, fill_buffer, chunk, actual); + current += chunk; + unfilled -= chunk; + } + while (unfilled && !err); + } + if (err) + { + actual = 0U; + return err; + } + return Base::write_at(offset, buffer, length, actual); + } +}; + + +template <typename Base, std::uint8_t DefaultFiller = 0U, std::size_t FillBlock = 1024U> +using random_read_write_fill_wrapper = random_write_fill_wrapper<random_read_fill_wrapper<Base, DefaultFiller>, DefaultFiller, FillBlock>; + +} // namespace util + +#endif // MAME_LIB_UTIL_IOPROCSFILL_H diff --git a/src/lib/util/ioprocsfilter.cpp b/src/lib/util/ioprocsfilter.cpp new file mode 100644 index 00000000000..da67b8c41f2 --- /dev/null +++ b/src/lib/util/ioprocsfilter.cpp @@ -0,0 +1,598 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocs.h + + I/O filters + +***************************************************************************/ + +#include "ioprocsfilter.h" + +#include "ioprocs.h" + +#include <zlib.h> + +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <cstdint> +#include <limits> +#include <system_error> +#include <type_traits> +#include <utility> + + +namespace util { + +namespace { + +// helper class for holding zlib data + +class zlib_data +{ +protected: + zlib_data(std::size_t buffer_size) noexcept : + m_buffer_size(std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), buffer_size)) + { + assert(buffer_size); + } + + z_stream &get_z_stream() noexcept { return m_z_stream; } + z_stream const &get_z_stream() const noexcept { return m_z_stream; } + Bytef *get_buffer() noexcept { return m_buffer.get(); } + Bytef const *get_buffer() const noexcept { return m_buffer.get(); } + std::size_t get_buffer_size() const noexcept { return m_buffer_size; } + + bool input_empty() const noexcept { return !m_z_stream.avail_in; } + bool output_available() const noexcept { return bool(m_z_stream.avail_out); } + + void initialize_z_stream() noexcept + { + m_z_stream.zalloc = Z_NULL; + m_z_stream.zfree = Z_NULL; + m_z_stream.opaque = Z_NULL; + } + + std::error_condition allocate_buffer() noexcept + { + if (!m_buffer) + m_buffer.reset(new (std::nothrow) Bytef [m_buffer_size]); + return m_buffer ? std::error_condition() : std::errc::not_enough_memory; + } + + void release_buffer() noexcept + { + m_buffer.reset(); + } + + static std::error_condition convert_z_error(int err) noexcept + { + switch (err) + { + case Z_OK: + case Z_STREAM_END: + return std::error_condition(); + case Z_NEED_DICT: + return std::errc::invalid_argument; + case Z_ERRNO: + return std::error_condition(errno, std::generic_category()); + case Z_STREAM_ERROR: + return std::errc::invalid_argument; + case Z_DATA_ERROR: + return std::errc::invalid_argument; // TODO: revisit this error code + case Z_MEM_ERROR: + return std::errc::not_enough_memory; + case Z_BUF_ERROR: + return std::errc::operation_would_block; // TODO: revisit this error code (should be handled internally) + case Z_VERSION_ERROR: + return std::errc::invalid_argument; // TODO: revisit this error code (library ABI mismatch) + default: + return std::errc::io_error; // TODO: better default error code + } + } + +private: + z_stream m_z_stream; + std::unique_ptr<Bytef []> m_buffer; + std::size_t const m_buffer_size; +}; + + +// helper class for decompressing deflated data + +class inflate_data : private zlib_data +{ +protected: + using zlib_data::zlib_data; + + ~inflate_data() + { + if (m_inflate_initialized) + inflateEnd(&get_z_stream()); + } + + using zlib_data::input_empty; + + bool stream_initialized() const noexcept + { + return m_inflate_initialized; + } + + std::error_condition initialize_z_stream() noexcept + { + if (m_inflate_initialized) + return std::errc::invalid_argument; + std::error_condition err = allocate_buffer(); + if (err) + return err; + zlib_data::initialize_z_stream(); + int const zerr = inflateInit(&get_z_stream()); + if (Z_OK == zerr) + m_inflate_initialized = true; + return convert_z_error(zerr); + } + + std::error_condition close_z_stream() noexcept + { + if (!m_inflate_initialized) + return std::errc::invalid_argument; + int const zerr = inflateEnd(&get_z_stream()); + m_inflate_initialized = false; + return convert_z_error(zerr); + } + + std::error_condition decompress_some(bool &stream_end) noexcept + { + assert(m_inflate_initialized); + int const zerr = inflate(&get_z_stream(), Z_SYNC_FLUSH); + if (!get_z_stream().avail_in) + reset_input(); + stream_end = Z_STREAM_END == zerr; + return convert_z_error(zerr); + } + + std::size_t input_available() const noexcept + { + return std::size_t(get_z_stream().avail_in); + } + + void reset_input() noexcept + { + get_z_stream().next_in = get_buffer(); + get_z_stream().avail_in = 0U; + } + + std::pair<void *, std::size_t> get_unfilled_input() noexcept + { + assert(get_buffer()); + Bytef *const base = get_z_stream().next_in + get_z_stream().avail_in; + return std::make_pair(base, get_buffer() + get_buffer_size() - base); + } + + void add_input(std::size_t length) noexcept + { + assert(get_buffer()); + get_z_stream().avail_in += length; + assert((get_buffer() + get_buffer_size()) >= (get_z_stream().next_in + get_z_stream().avail_in)); + } + + std::size_t output_produced() const noexcept + { + return m_output_max - get_z_stream().avail_out; + } + + void set_output(void *buffer, std::size_t length) noexcept + { + m_output_max = std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), length); + get_z_stream().next_out = reinterpret_cast<Bytef *>(buffer); + get_z_stream().avail_out = uInt(m_output_max); + } + +private: + std::error_condition allocate_buffer() noexcept + { + std::error_condition err; + if (!get_buffer()) + { + err = zlib_data::allocate_buffer(); + reset_input(); + } + return err; + } + + bool m_inflate_initialized = false; + std::size_t m_output_max = 0U; +}; + + +// helper class for deflating data + +class deflate_data : private zlib_data +{ +protected: + deflate_data(int level, std::size_t buffer_size) noexcept : zlib_data(buffer_size), m_level(level) + { + } + + ~deflate_data() + { + if (m_deflate_initialized) + deflateEnd(&get_z_stream()); + } + + using zlib_data::input_empty; + using zlib_data::output_available; + + bool stream_initialized() const noexcept + { + return m_deflate_initialized; + } + + bool compression_finished() const noexcept + { + return m_compression_finished; + } + + std::error_condition initialize_z_stream() noexcept + { + if (m_deflate_initialized) + return std::errc::invalid_argument; + std::error_condition err = allocate_buffer(); + if (err) + return err; + zlib_data::initialize_z_stream(); + int const zerr = deflateInit(&get_z_stream(), m_level); + reset_output(); + if (Z_OK == zerr) + m_deflate_initialized = true; + return convert_z_error(zerr); + } + + std::error_condition close_z_stream() noexcept + { + if (!m_deflate_initialized) + return std::errc::invalid_argument; + m_deflate_initialized = m_compression_finished = false; + return convert_z_error(deflateEnd(&get_z_stream())); + } + + std::error_condition reset_z_stream() noexcept + { + if (!m_deflate_initialized) + return std::errc::invalid_argument; + assert(get_buffer()); + reset_output(); + m_compression_finished = false; + return convert_z_error(deflateReset(&get_z_stream())); + } + + std::error_condition compress_some() noexcept + { + assert(m_deflate_initialized); + return convert_z_error(deflate(&get_z_stream(), Z_NO_FLUSH)); + } + + std::error_condition finish_compression() noexcept + { + assert(m_deflate_initialized); + int const zerr = deflate(&get_z_stream(), Z_FINISH); + if (Z_STREAM_END == zerr) + m_compression_finished = true; + return convert_z_error(zerr); + } + + std::size_t input_used() const noexcept + { + return m_input_max - get_z_stream().avail_in; + } + + void set_input(void const *data, std::size_t length) noexcept + { + m_input_max = std::min<std::common_type_t<uInt, std::size_t> >(std::numeric_limits<uInt>::max(), length); + get_z_stream().next_in = const_cast<Bytef z_const *>(reinterpret_cast<Bytef const *>(data)); + get_z_stream().avail_in = uInt(m_input_max); + } + + std::pair<void const *, std::size_t> get_output() const noexcept + { + assert(get_buffer()); + return std::make_pair( + &get_buffer()[m_output_used], + get_buffer_size() - get_z_stream().avail_out - m_output_used); + } + + void consume_output(std::size_t length) noexcept + { + m_output_used += length; + assert(m_output_used <= (get_buffer_size() - get_z_stream().avail_out)); + if (m_output_used == (get_buffer_size() - get_z_stream().avail_out)) + reset_output(); + } + +private: + void reset_output() noexcept + { + assert(get_buffer()); + m_output_used = 0U; + get_z_stream().next_out = get_buffer(); + get_z_stream().avail_out = uInt(get_buffer_size()); + } + + int const m_level; + bool m_deflate_initialized = false; + bool m_compression_finished = false; + std::size_t m_output_used = 0U; + std::size_t m_input_max = 0U; +}; + + +// helper for holding an object and deleting it (or not) as necessary + +template <typename T> +class filter_base +{ +protected: + filter_base(std::unique_ptr<T> &&object) noexcept : m_object(object.release()), m_owned(true) + { + assert(m_object); + } + + filter_base(T &object) noexcept : m_object(&object), m_owned(false) + { + } + + ~filter_base() + { + if (m_owned) + delete m_object; + } + + T &object() noexcept + { + return *m_object; + } + +private: + T *const m_object; + bool const m_owned; +}; + + +// filter for decompressing deflated data + +template <typename Stream> +class zlib_read_filter : public read_stream, protected filter_base<Stream>, protected inflate_data +{ +public: + zlib_read_filter(std::unique_ptr<Stream> &&stream, std::size_t read_chunk) noexcept : + filter_base<Stream>(std::move(stream)), + inflate_data(read_chunk) + { + } + + zlib_read_filter(Stream &stream, std::size_t read_chunk) noexcept : + filter_base<Stream>(stream), + inflate_data(read_chunk) + { + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err; + actual = 0U; + + if (!stream_initialized()) + err = initialize_z_stream(); + + if (!err && (length > actual)) + { + bool short_input = false; + do + { + if (input_empty()) + { + auto const space = get_unfilled_input(); + std::size_t filled; + err = this->object().read(space.first, space.second, filled); + add_input(filled); + short_input = space.second > filled; + } + + if (!err && !input_empty()) + { + set_output(reinterpret_cast<std::uint8_t *>(buffer) + actual, length - actual); + bool stream_end; + err = decompress_some(stream_end); + actual += output_produced(); + + if (stream_end) + { + assert(!err); + if constexpr (std::is_base_of_v<random_read, Stream>) + { + if (!input_empty()) + { + std::int64_t const overshoot = std::uint64_t(input_available()); + reset_input(); + return this->object().seek(-overshoot, SEEK_CUR); + } + } + else + { + return std::error_condition(); + } + } + } + } + while (!err && (length > actual) && !short_input); + } + + return err; + } +}; + + +// filter for deflating data + +class zlib_write_filter : public write_stream, protected filter_base<write_stream>, protected deflate_data +{ +public: + zlib_write_filter(write_stream::ptr &&stream, int level, std::size_t buffer_size) noexcept : + filter_base<write_stream>(std::move(stream)), + deflate_data(level, buffer_size) + { + } + + zlib_write_filter(write_stream &stream, int level, std::size_t buffer_size) noexcept : + filter_base<write_stream>(stream), + deflate_data(level, buffer_size) + { + } + + ~zlib_write_filter() + { + finalize(); + } + + virtual std::error_condition finalize() noexcept override + { + if (!stream_initialized()) + return std::error_condition(); + + do + { + if (!compression_finished() && output_available()) + { + std::error_condition err = finish_compression(); + if (err) + return err; + } + + while ((compression_finished() && get_output().second) || !output_available()) + { + std::error_condition err = write_some(); + if (err) + return err; + } + } + while (!compression_finished()); + + return close_z_stream(); + } + + virtual std::error_condition flush() noexcept override + { + if (stream_initialized()) + { + auto const output = get_output(); + if (output.second) + { + std::size_t written; + std::error_condition err = object().write(output.first, output.second, written); + consume_output(written); + if (err) + { + object().flush(); + return err; + } + } + } + return object().flush(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition err; + actual = 0U; + + if (!stream_initialized()) + { + err = initialize_z_stream(); + } + else if (compression_finished()) + { + while (!err && get_output().second) + err = write_some(); + if (!err) + err = reset_z_stream(); + } + + while (!err && (length > actual)) + { + set_input(reinterpret_cast<std::uint8_t const *>(buffer) + actual, length - actual); + do + { + if (output_available()) + err = compress_some(); + + while (!err && !output_available()) + err = write_some(); + } + while (!err && !input_empty()); + actual += input_used(); + } + + return err; + } + +private: + std::error_condition write_some() noexcept + { + auto const output = get_output(); + std::size_t written; + std::error_condition err = object().write(output.first, output.second, written); + consume_output(written); + return err; + } +}; + +} // anonymous namespace + + +// creating decompressing filters + +read_stream::ptr zlib_read(read_stream::ptr &&stream, std::size_t read_chunk) noexcept +{ + read_stream::ptr result; + if (stream) + result.reset(new (std::nothrow) zlib_read_filter<read_stream>(std::move(stream), read_chunk)); + return result; +} + +read_stream::ptr zlib_read(random_read::ptr &&stream, std::size_t read_chunk) noexcept +{ + read_stream::ptr result; + if (stream) + result.reset(new (std::nothrow) zlib_read_filter<random_read>(std::move(stream), read_chunk)); + return result; +} + +read_stream::ptr zlib_read(read_stream &stream, std::size_t read_chunk) noexcept +{ + return read_stream::ptr(new (std::nothrow) zlib_read_filter<read_stream>(stream, read_chunk)); +} + +read_stream::ptr zlib_read(random_read &stream, std::size_t read_chunk) noexcept +{ + return read_stream::ptr(new (std::nothrow) zlib_read_filter<random_read>(stream, read_chunk)); +} + + +// creating compressing filters + +write_stream::ptr zlib_write(write_stream::ptr &&stream, int level, std::size_t buffer_size) noexcept +{ + write_stream::ptr result; + if (stream) + result.reset(new (std::nothrow) zlib_write_filter(std::move(stream), level, buffer_size)); + return result; +} + +write_stream::ptr zlib_write(write_stream &stream, int level, std::size_t buffer_size) noexcept +{ + return write_stream::ptr(new (std::nothrow) zlib_write_filter(stream, level, buffer_size)); +} + +} // namespace util diff --git a/src/lib/util/ioprocsfilter.h b/src/lib/util/ioprocsfilter.h new file mode 100644 index 00000000000..a146dd737ce --- /dev/null +++ b/src/lib/util/ioprocsfilter.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocs.h + + I/O filters + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_IOPROCSFILTER_H +#define MAME_LIB_UTIL_IOPROCSFILTER_H + +#include "utilfwd.h" + +#include <cstdlib> +#include <memory> + + +namespace util { + +std::unique_ptr<read_stream> zlib_read(std::unique_ptr<read_stream> &&stream, std::size_t read_chunk) noexcept; +std::unique_ptr<read_stream> zlib_read(std::unique_ptr<random_read> &&stream, std::size_t read_chunk) noexcept; +std::unique_ptr<read_stream> zlib_read(read_stream &stream, std::size_t read_chunk) noexcept; +std::unique_ptr<read_stream> zlib_read(random_read &stream, std::size_t read_chunk) noexcept; + +std::unique_ptr<write_stream> zlib_write(std::unique_ptr<write_stream> &&stream, int level, std::size_t buffer_size) noexcept; +std::unique_ptr<write_stream> zlib_write(write_stream &stream, int level, std::size_t buffer_size) noexcept; + +} // namespace util + +#endif // MAME_LIB_UTIL_IOPROCSFILTER_H diff --git a/src/lib/util/ioprocsvec.h b/src/lib/util/ioprocsvec.h new file mode 100644 index 00000000000..27dda095ad3 --- /dev/null +++ b/src/lib/util/ioprocsvec.h @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + ioprocsvec.h + + Helper for using a vector as an in-memory file + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_IOPROCSVEC_H +#define MAME_LIB_UTIL_IOPROCSVEC_H + +#include "ioprocs.h" + +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <limits> +#include <system_error> +#include <type_traits> +#include <vector> + + +namespace util { + +template <typename T = std::uint8_t> +class vector_read_write_adapter : public random_read_write +{ +public: + vector_read_write_adapter(std::vector<T> &storage) noexcept : m_storage(storage) + { + check_resized(); + } + + virtual std::error_condition seek(std::int64_t offset, int whence) noexcept override + { + switch (whence) + { + case SEEK_SET: + if (0 > offset) + return std::errc::invalid_argument; + m_pointer = std::uint64_t(offset); + return std::error_condition(); + + case SEEK_CUR: + if (0 > offset) + { + if (std::uint64_t(-offset) > m_pointer) + return std::errc::invalid_argument; + } + else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_pointer) + { + return std::errc::invalid_argument; + } + m_pointer += offset; + return std::error_condition(); + + case SEEK_END: + check_resized(); + if (0 > offset) + { + if (std::uint64_t(-offset) > m_size) + return std::errc::invalid_argument; + } + else if ((std::numeric_limits<std::uint64_t>::max() - offset) < m_size) + { + return std::errc::invalid_argument; + } + m_pointer = std::uint64_t(m_size) + offset; + return std::error_condition(); + + default: + return std::errc::invalid_argument; + } + } + + virtual std::error_condition tell(std::uint64_t &result) noexcept override + { + result = m_pointer; + return std::error_condition(); + } + + virtual std::error_condition length(std::uint64_t &result) noexcept override + { + check_resized(); + if (std::numeric_limits<uint64_t>::max() < m_size) + return std::errc::file_too_large; + + result = m_size; + return std::error_condition(); + } + + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + do_read(m_pointer, buffer, length, actual); + m_pointer += actual; + return std::error_condition(); + } + + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + { + do_read(offset, buffer, length, actual); + return std::error_condition(); + } + + virtual std::error_condition finalize() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition flush() noexcept override + { + return std::error_condition(); + } + + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + std::error_condition result = do_write(m_pointer, buffer, length, actual); + m_pointer += actual; + return result; + } + + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + { + return do_write(offset, buffer, length, actual); + } + +private: + using elements_type = typename std::vector<T>::size_type; + using common_size_type = std::common_type_t<std::uint64_t, std::size_t>; + + void check_resized() noexcept + { + if (m_storage.size() != m_elements) + { + m_elements = m_storage.size(); + m_size = m_elements * sizeof(T); + } + } + + void do_read(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept + { + check_resized(); + if ((offset < m_size) && length) + { + actual = std::min(std::size_t(m_size - offset), length); + std::memmove(buffer, reinterpret_cast<std::uint8_t *>(m_storage.data()) + offset, actual); + } + else + { + actual = 0U; + } + } + + std::error_condition do_write(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept + { + check_resized(); + std::size_t allocated = m_elements * sizeof(T); + std::uint64_t const target = ((std::numeric_limits<std::uint64_t>::max() - offset) >= length) + ? (offset + length) + : std::numeric_limits<std::uint64_t>::max(); + + std::error_condition result; + if (target > allocated) + { + elements_type const required = std::min<std::common_type_t<elements_type, std::uint64_t> >( + std::numeric_limits<elements_type>::max(), + (target + sizeof(T) - 1) / sizeof(T)); // technically can overflow but unlikely + try { m_storage.resize(required); } // unpredictable if constructing/assigning T can throw + catch (...) { result = std::errc::not_enough_memory; } + m_elements = m_storage.size(); + allocated = m_elements * sizeof(T); + assert(allocated >= m_size); + + if (offset > m_size) + { + std::size_t const new_size = std::size_t(std::min<common_size_type>(allocated, offset)); + std::memset( + reinterpret_cast<std::uint8_t *>(m_storage.data()) + m_size, + 0x00, // POSIX says unwritten areas of files should read as zero + new_size - m_size); + m_size = new_size; + } + } + + std::size_t const limit = std::min<common_size_type>(target, allocated); + if (limit > offset) + { + actual = std::size_t(limit - offset); + std::memmove(reinterpret_cast<std::uint8_t *>(m_storage.data()) + offset, buffer, actual); + m_size = limit; + } + else + { + actual = 0U; + } + if (!result && (actual < length)) + result = std::errc::no_space_on_device; + + return result; + } + + std::vector<T> &m_storage; + std::uint64_t m_pointer = 0U; + elements_type m_elements = 0U; + std::size_t m_size = 0U; +}; + +} // namespace util + +#endif // MAME_LIB_UTIL_IOPROCSVEC_H diff --git a/src/lib/util/path.cpp b/src/lib/util/path.cpp new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/lib/util/path.cpp diff --git a/src/lib/util/path.h b/src/lib/util/path.h new file mode 100644 index 00000000000..1291d7b17d3 --- /dev/null +++ b/src/lib/util/path.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + path.h + + Filesystem path utilties + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_PATH_H +#define MAME_LIB_UTIL_PATH_H + +#include "osdfile.h" // for PATH_SEPARATOR + +#include <string> +#include <utility> + + +namespace util { + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +// is a given character a directory separator? + +constexpr bool is_directory_separator(char c) +{ +#if defined(WIN32) + return ('\\' == c) || ('/' == c) || (':' == c); +#else + return '/' == c; +#endif +} + + +// append to a path + +template <typename T, typename... U> +inline std::string &path_append(std::string &path, T &&next, U &&... more) +{ + if (!path.empty() && !is_directory_separator(path.back())) + path.append(PATH_SEPARATOR); + path.append(std::forward<T>(next)); + if constexpr (sizeof...(U)) + return path_append(std::forward<U>(more)...); + else + return path; +} + + +// concatenate paths + +template <typename T, typename... U> +inline std::string path_concat(T &&first, U &&... more) +{ + std::string result(std::forward<T>(first)); + if constexpr (sizeof...(U)) + path_append(result, std::forward<U>(more)...); + return result; +} + +} // namespace util + +#endif // MAME_LIB_UTIL_PATH_H diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h index b8c9b4f1a99..a3ba1d11261 100644 --- a/src/lib/util/strformat.h +++ b/src/lib/util/strformat.h @@ -578,16 +578,16 @@ template <typename Stream, typename T> class format_output { private: - template <typename U> struct string_semantics - { static constexpr bool value = false; }; - template <typename CharT, typename Traits, typename Allocator> struct string_semantics<std::basic_string<CharT, Traits, Allocator> > - { static constexpr bool value = true; }; - template <typename CharT, typename Traits> struct string_semantics<std::basic_string_view<CharT, Traits> > - { static constexpr bool value = true; }; - template <typename U> struct signed_integer_semantics - { static constexpr bool value = std::is_integral_v<U>&& std::is_signed_v<U>; }; - template <typename U> struct unsigned_integer_semantics - { static constexpr bool value = std::is_integral_v<U>&& !std::is_signed_v<U>; }; + template <typename U> + struct string_semantics : public std::false_type { }; + template <typename CharT, typename Traits, typename Allocator> + struct string_semantics<std::basic_string<CharT, Traits, Allocator> > : public std::true_type { }; + template <typename CharT, typename Traits> + struct string_semantics<std::basic_string_view<CharT, Traits> > : public std::true_type { }; + template <typename U> + using signed_integer_semantics = std::bool_constant<std::is_integral_v<U> && std::is_signed_v<U> >; + template <typename U> + using unsigned_integer_semantics = std::bool_constant<std::is_integral_v<U> && !std::is_signed_v<U> >; static void apply_signed(Stream &str, char16_t const &value) { @@ -865,8 +865,8 @@ template <typename Stream, typename T> class format_output<Stream, T *> { protected: - template <typename U> struct string_semantics - { static constexpr bool value = std::is_same<std::remove_const_t<U>, typename Stream::char_type>::value; }; + template <typename U> + using string_semantics = std::bool_constant<std::is_same_v<std::remove_const_t<U>, typename Stream::char_type> >; public: template <typename U> @@ -940,10 +940,10 @@ template <typename T> class format_make_integer { private: - template <typename U> struct use_unsigned_cast - { static constexpr bool value = std::is_convertible<U const, unsigned>::value && std::is_unsigned<U>::value; }; - template <typename U> struct use_signed_cast - { static constexpr bool value = !use_unsigned_cast<U>::value && std::is_convertible<U const, int>::value; }; + template <typename U> + using use_unsigned_cast = std::bool_constant<std::is_convertible_v<U const, unsigned> && std::is_unsigned_v<U> >; + template <typename U> + using use_signed_cast = std::bool_constant<!use_unsigned_cast<U>::value && std::is_convertible_v<U const, int> >; public: template <typename U> static bool apply(U const &value, int &result) @@ -974,14 +974,14 @@ template <typename T> class format_store_integer { private: - template <typename U> struct is_non_const_ptr - { static constexpr bool value = std::is_pointer<U>::value && !std::is_const<std::remove_pointer_t<U> >::value; }; - template <typename U> struct is_unsigned_ptr - { static constexpr bool value = std::is_pointer<U>::value && std::is_unsigned<std::remove_pointer_t<U> >::value; }; - template <typename U> struct use_unsigned_cast - { static constexpr bool value = is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> >::value; }; - template <typename U> struct use_signed_cast - { static constexpr bool value = is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible<std::streamoff, std::remove_pointer_t<U> >::value; }; + template <typename U> + using is_non_const_ptr = std::bool_constant<std::is_pointer_v<U> && !std::is_const_v<std::remove_pointer_t<U> > >; + template <typename U> + using is_unsigned_ptr = std::bool_constant<std::is_pointer_v<U> && std::is_unsigned_v<std::remove_pointer_t<U> > >; + template <typename U> + using use_unsigned_cast = std::bool_constant<is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible_v<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> > >; + template <typename U> + using use_signed_cast = std::bool_constant<is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible_v<std::streamoff, std::remove_pointer_t<U> > >; public: template <typename U> static bool apply(U const &value, std::streamoff data) @@ -1091,11 +1091,11 @@ public: protected: template <typename T> - struct handle_char_ptr { static constexpr bool value = std::is_pointer<T>::value && std::is_same<std::remove_cv_t<std::remove_pointer_t<T> >, char_type>::value; }; + using handle_char_ptr = std::bool_constant<std::is_pointer_v<T> && std::is_same_v<std::remove_cv_t<std::remove_pointer_t<T> >, char_type> >; template <typename T> - struct handle_char_array { static constexpr bool value = std::is_array<T>::value && std::is_same<std::remove_cv_t<std::remove_extent_t<T> >, char_type>::value; }; + using handle_char_array = std::bool_constant<std::is_array_v<T> && std::is_same_v<std::remove_cv_t<std::remove_extent_t<T> >, char_type> >; template <typename T> - struct handle_container { static constexpr bool value = !handle_char_ptr<T>::value && !handle_char_array<T>::value; }; + using handle_container = std::bool_constant<!handle_char_ptr<T>::value && !handle_char_array<T>::value>; template <typename Format> format_argument_pack( diff --git a/src/lib/util/timeconv.cpp b/src/lib/util/timeconv.cpp index 99953712003..469b6b592a2 100644 --- a/src/lib/util/timeconv.cpp +++ b/src/lib/util/timeconv.cpp @@ -14,42 +14,10 @@ namespace util { -/*************************************************************************** - PROTOTYPES -***************************************************************************/ - -static std::chrono::system_clock::duration calculate_system_clock_adjustment(); - - -/*************************************************************************** - GLOBAL VARIABLES -***************************************************************************/ - -std::chrono::system_clock::duration system_clock_adjustment(calculate_system_clock_adjustment()); - - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -arbitrary_datetime arbitrary_datetime::now() -{ - time_t sec; - time(&sec); - auto t = *localtime(&sec); - - arbitrary_datetime dt; - dt.year = t.tm_year + 1900; - dt.month = t.tm_mon + 1; - dt.day_of_month = t.tm_mday; - dt.hour = t.tm_hour; - dt.minute = t.tm_min; - dt.second = t.tm_sec; - return dt; -} +namespace { -static std::chrono::system_clock::duration calculate_system_clock_adjustment() +std::chrono::system_clock::duration calculate_system_clock_adjustment() { constexpr auto days_in_year(365); constexpr auto days_in_four_years((days_in_year * 4) + 1); @@ -84,6 +52,39 @@ static std::chrono::system_clock::duration calculate_system_clock_adjustment() return result - std::chrono::system_clock::from_time_t(0).time_since_epoch(); } +} // anonymous namespace + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +std::chrono::system_clock::duration system_clock_adjustment(calculate_system_clock_adjustment()); + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +arbitrary_datetime arbitrary_datetime::now() +{ + time_t sec; + time(&sec); + auto t = *localtime(&sec); + + arbitrary_datetime dt; + dt.year = t.tm_year + 1900; + dt.month = t.tm_mon + 1; + dt.day_of_month = t.tm_mday; + dt.hour = t.tm_hour; + dt.minute = t.tm_min; + dt.second = t.tm_sec; + + return dt; +} + // ------------------------------------------------- diff --git a/src/lib/util/timeconv.h b/src/lib/util/timeconv.h index f9d1b070012..91327dbac16 100644 --- a/src/lib/util/timeconv.h +++ b/src/lib/util/timeconv.h @@ -22,6 +22,7 @@ namespace util { + /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ @@ -58,7 +59,7 @@ struct arbitrary_datetime // date of the epoch's begining //--------------------------------------------------------- -template<typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio> +template <typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio> class arbitrary_clock { public: @@ -89,7 +90,7 @@ public: // with a different scale to this arbitrary_clock's scale //--------------------------------------------------------- - template<typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2> + template <typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2> static time_point from_arbitrary_time_point(const std::chrono::time_point<arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2> > &tp) { arbitrary_datetime dt; @@ -111,7 +112,7 @@ public: // of this scale to one of different scale //--------------------------------------------------------- - template<typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2> + template <typename Rep2, int YY, int MM, int DD, int HH, int NN, int SS, typename Ratio2> static std::chrono::time_point<arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2> > to_arbitrary_time_point(const time_point &tp) { return arbitrary_clock<Rep2, YY, MM, DD, HH, NN, SS, Ratio2>::from_arbitrary_time_point(tp); @@ -125,14 +126,14 @@ public: static struct tm to_tm(const time_point &tp) { std::chrono::time_point<tm_conversion_clock> normalized_tp = to_arbitrary_time_point< - std::int64_t, - tm_conversion_clock::base_year, - tm_conversion_clock::base_month, - tm_conversion_clock::base_day, - tm_conversion_clock::base_hour, - tm_conversion_clock::base_minute, - tm_conversion_clock::base_second, - tm_conversion_clock::period>(tp); + std::int64_t, + tm_conversion_clock::base_year, + tm_conversion_clock::base_month, + tm_conversion_clock::base_day, + tm_conversion_clock::base_hour, + tm_conversion_clock::base_minute, + tm_conversion_clock::base_second, + tm_conversion_clock::period>(tp); return internal_to_tm(normalized_tp.time_since_epoch()); } @@ -144,14 +145,14 @@ public: static std::chrono::time_point<std::chrono::system_clock> to_system_clock(const time_point &tp) { auto normalized_tp = to_arbitrary_time_point< - std::int64_t, - system_conversion_clock::base_year, - system_conversion_clock::base_month, - system_conversion_clock::base_day, - system_conversion_clock::base_hour, - system_conversion_clock::base_minute, - system_conversion_clock::base_second, - system_conversion_clock::period>(tp); + std::int64_t, + system_conversion_clock::base_year, + system_conversion_clock::base_month, + system_conversion_clock::base_day, + system_conversion_clock::base_hour, + system_conversion_clock::base_minute, + system_conversion_clock::base_second, + system_conversion_clock::period>(tp); return std::chrono::time_point<std::chrono::system_clock>(normalized_tp.time_since_epoch() + system_clock_adjustment); } diff --git a/src/lib/util/un7z.cpp b/src/lib/util/un7z.cpp index 879da294c69..b35af479d5d 100644 --- a/src/lib/util/un7z.cpp +++ b/src/lib/util/un7z.cpp @@ -13,11 +13,13 @@ #include "unzip.h" #include "corestr.h" -#include "osdcore.h" -#include "osdfile.h" +#include "ioprocs.h" #include "unicode.h" #include "timeconv.h" +#include "osdcore.h" +#include "osdfile.h" + #include "lzma/C/7z.h" #include "lzma/C/7zAlloc.h" #include "lzma/C/7zCrc.h" @@ -38,47 +40,71 @@ namespace util { + namespace { + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ -struct CSzFile +struct CFileInStream : public ISeekInStream { - CSzFile() : currfpos(0), length(0), osdfile() {} + CFileInStream() noexcept + { + Read = [] (void *pp, void *buf, size_t *size) { return reinterpret_cast<CFileInStream *>(pp)->read(buf, *size); }; + Seek = [] (void *pp, Int64 *pos, ESzSeek origin) { return reinterpret_cast<CFileInStream *>(pp)->seek(*pos, origin); }; + } - std::uint64_t currfpos; - std::uint64_t length; - osd_file::ptr osdfile; + random_read::ptr file; + std::uint64_t currfpos = 0; + std::uint64_t length = 0; - SRes read(void *data, std::size_t &size) +private: + SRes read(void *data, std::size_t &size) noexcept { - if (!osdfile) + if (!file) { - osd_printf_error("un7z: called CSzFile::read without file\n"); + osd_printf_error("un7z: called CFileInStream::read without file\n"); return SZ_ERROR_READ; } if (!size) return SZ_OK; - // TODO: this casts a size_t to a uint32_t, so it will fail if >=4GB is requested at once (need a loop) - std::uint32_t read_length(0); - auto const err = osdfile->read(data, currfpos, size, read_length); + std::size_t read_length(0); + std::error_condition const err = file->read_at(currfpos, data, size, read_length); size = read_length; currfpos += read_length; - return (osd_file::error::NONE == err) ? SZ_OK : SZ_ERROR_READ; + return !err ? SZ_OK : SZ_ERROR_READ; } - SRes seek(Int64 &pos, ESzSeek origin) + SRes seek(Int64 &pos, ESzSeek origin) noexcept { + // need to synthesise this because the OSD file wrapper doesn't implement SEEK_END switch (origin) { - case SZ_SEEK_CUR: currfpos += pos; break; - case SZ_SEEK_SET: currfpos = pos; break; - case SZ_SEEK_END: currfpos = length + pos; break; - default: return SZ_ERROR_READ; + case SZ_SEEK_CUR: + if ((0 > pos) && (-pos > currfpos)) + { + osd_printf_error("un7z: attemped to seek back %d bytes when current offset is %u\n", -pos, currfpos); + return SZ_ERROR_READ; + } + currfpos += pos; + break; + case SZ_SEEK_SET: + currfpos = pos; + break; + case SZ_SEEK_END: + if ((0 > pos) && (-pos > length)) + { + osd_printf_error("un7z: attemped to seek %d bytes before end of file %u\n", -pos, currfpos); + return SZ_ERROR_READ; + } + currfpos = length + pos; + break; + default: + return SZ_ERROR_READ; } pos = currfpos; return SZ_OK; @@ -86,18 +112,18 @@ struct CSzFile }; -struct CFileInStream : public ISeekInStream, public CSzFile -{ - CFileInStream(); -}; - - -class m7z_file_impl +class m7z_file_impl { public: typedef std::unique_ptr<m7z_file_impl> ptr; - m7z_file_impl(const std::string &filename); + m7z_file_impl(std::string &&filename) noexcept; + + m7z_file_impl(random_read::ptr &&file) noexcept + : m7z_file_impl(std::string()) + { + m_archive_stream.file = std::move(file); + } virtual ~m7z_file_impl() { @@ -107,7 +133,7 @@ public: SzArEx_Free(&m_db, &m_alloc_imp); } - static ptr find_cached(const std::string &filename) + static ptr find_cached(std::string_view filename) noexcept { std::lock_guard<std::mutex> guard(s_cache_mutex); for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++) @@ -115,47 +141,60 @@ public: // if we have a valid entry and it matches our filename, use it and remove from the cache if (s_cache[cachenum] && (filename == s_cache[cachenum]->m_filename)) { + using std::swap; ptr result; - std::swap(s_cache[cachenum], result); + swap(s_cache[cachenum], result); osd_printf_verbose("un7z: found %s in cache\n", filename); return result; } } return ptr(); } - static void close(ptr &&archive); - static void cache_clear() + + static void close(ptr &&archive) noexcept; + + static void cache_clear() noexcept { // clear call cache entries std::lock_guard<std::mutex> guard(s_cache_mutex); - for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { } + for (auto &cached : s_cache) + cached.reset(); } - archive_file::error initialize(); + std::error_condition initialize() noexcept; - int first_file() { return search(0, 0, std::string(), false, false, false); } - int next_file() { return (m_curr_file_idx < 0) ? -1 : search(m_curr_file_idx + 1, 0, std::string(), false, false, false); } + int first_file() noexcept + { + return search(0, 0, std::string_view(), false, false, false); + } - int search(std::uint32_t crc) + int next_file() noexcept { - return search(0, crc, std::string(), true, false, false); + return (m_curr_file_idx < 0) ? -1 : search(m_curr_file_idx + 1, 0, std::string_view(), false, false, false); } - int search(const std::string &filename, bool partialpath) + + int search(std::uint32_t crc) noexcept + { + return search(0, crc, std::string_view(), true, false, false); + } + + int search(std::string_view filename, bool partialpath) noexcept { return search(0, 0, filename, false, true, partialpath); } - int search(std::uint32_t crc, const std::string &filename, bool partialpath) + + int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept { return search(0, crc, filename, true, true, partialpath); } - bool current_is_directory() const { return m_curr_is_dir; } - const std::string ¤t_name() const { return m_curr_name; } - std::uint64_t current_uncompressed_length() const { return m_curr_length; } - virtual std::chrono::system_clock::time_point current_last_modified() const { return m_curr_modified; } - std::uint32_t current_crc() const { return m_curr_crc; } + bool current_is_directory() const noexcept { return m_curr_is_dir; } + const std::string ¤t_name() const noexcept { return m_curr_name; } + std::uint64_t current_uncompressed_length() const noexcept { return m_curr_length; } + virtual std::chrono::system_clock::time_point current_last_modified() const noexcept { return m_curr_modified; } + std::uint32_t current_crc() const noexcept { return m_curr_crc; } - archive_file::error decompress(void *buffer, std::uint32_t length); + std::error_condition decompress(void *buffer, std::size_t length) noexcept; private: m7z_file_impl(const m7z_file_impl &) = delete; @@ -166,12 +205,12 @@ private: int search( int i, std::uint32_t search_crc, - const std::string &search_filename, + std::string_view search_filename, bool matchcrc, bool matchname, - bool partialpath); + bool partialpath) noexcept; void make_utf8_name(int index); - void set_curr_modified(); + void set_curr_modified() noexcept; static constexpr std::size_t CACHE_SIZE = 8; static std::array<ptr, CACHE_SIZE> s_cache; @@ -187,7 +226,7 @@ private: std::uint32_t m_curr_crc; // current file crc std::vector<UInt16> m_utf16_buf; - std::vector<char32_t> m_uchar_buf; + std::vector<char32_t> m_uchar_buf; std::vector<char> m_utf8_buf; CFileInStream m_archive_stream; @@ -201,39 +240,38 @@ private: UInt32 m_block_index; Byte * m_out_buffer; std::size_t m_out_buffer_size; - }; class m7z_file_wrapper : public archive_file { public: - m7z_file_wrapper(m7z_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); } + m7z_file_wrapper(m7z_file_impl::ptr &&impl) noexcept : m_impl(std::move(impl)) { assert(m_impl); } virtual ~m7z_file_wrapper() override { m7z_file_impl::close(std::move(m_impl)); } - virtual int first_file() override { return m_impl->first_file(); } - virtual int next_file() override { return m_impl->next_file(); } + virtual int first_file() noexcept override { return m_impl->first_file(); } + virtual int next_file() noexcept override { return m_impl->next_file(); } - virtual int search(std::uint32_t crc) override + virtual int search(std::uint32_t crc) noexcept override { return m_impl->search(crc); } - virtual int search(const std::string &filename, bool partialpath) override + virtual int search(std::string_view filename, bool partialpath) noexcept override { return m_impl->search(filename, partialpath); } - virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) override + virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept override { return m_impl->search(crc, filename, partialpath); } - virtual bool current_is_directory() const override { return m_impl->current_is_directory(); } - virtual const std::string ¤t_name() const override { return m_impl->current_name(); } - virtual std::uint64_t current_uncompressed_length() const override { return m_impl->current_uncompressed_length(); } - virtual std::chrono::system_clock::time_point current_last_modified() const override { return m_impl->current_last_modified(); } - virtual std::uint32_t current_crc() const override { return m_impl->current_crc(); } + virtual bool current_is_directory() const noexcept override { return m_impl->current_is_directory(); } + virtual const std::string ¤t_name() const noexcept override { return m_impl->current_name(); } + virtual std::uint64_t current_uncompressed_length() const noexcept override { return m_impl->current_uncompressed_length(); } + virtual std::chrono::system_clock::time_point current_last_modified() const noexcept override { return m_impl->current_last_modified(); } + virtual std::uint32_t current_crc() const noexcept override { return m_impl->current_crc(); } - virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); } + virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept override { return m_impl->decompress(buffer, length); } private: m7z_file_impl::ptr m_impl; @@ -251,48 +289,20 @@ std::mutex m7z_file_impl::s_cache_mutex; /*************************************************************************** - 7Zip Memory / File handling (adapted from 7zfile.c/.h and 7zalloc.c/.h) -***************************************************************************/ - -/* ---------- FileInStream ---------- */ - -extern "C" { -static SRes FileInStream_Read(void *pp, void *buf, size_t *size) -{ - return (reinterpret_cast<CFileInStream *>(pp)->read(buf, *size) == 0) ? SZ_OK : SZ_ERROR_READ; -} - -static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) -{ - return reinterpret_cast<CFileInStream *>(pp)->seek(*pos, origin); -} - -} // extern "C" - - -CFileInStream::CFileInStream() -{ - Read = &FileInStream_Read; - Seek = &FileInStream_Seek; -} - - - -/*************************************************************************** CACHE MANAGEMENT ***************************************************************************/ -m7z_file_impl::m7z_file_impl(const std::string &filename) - : m_filename(filename) +m7z_file_impl::m7z_file_impl(std::string &&filename) noexcept + : m_filename(std::move(filename)) , m_curr_file_idx(-1) , m_curr_is_dir(false) , m_curr_name() , m_curr_length(0) , m_curr_modified() , m_curr_crc(0) - , m_utf16_buf(128) - , m_uchar_buf(128) - , m_utf8_buf(512) + , m_utf16_buf() + , m_uchar_buf() + , m_utf8_buf() , m_inited(false) , m_block_index(0) , m_out_buffer(nullptr) @@ -310,15 +320,45 @@ m7z_file_impl::m7z_file_impl(const std::string &filename) } -archive_file::error m7z_file_impl::initialize() +std::error_condition m7z_file_impl::initialize() noexcept { - osd_file::error const err = osd_file::open(m_filename, OPEN_FLAG_READ, m_archive_stream.osdfile, m_archive_stream.length); - if (err != osd_file::error::NONE) - return archive_file::error::FILE_ERROR; + try + { + if (m_utf16_buf.size() < 128) + m_utf16_buf.resize(128); + if (m_uchar_buf.size() < 128) + m_uchar_buf.resize(128); + m_utf8_buf.reserve(512); + } + catch (...) + { + return std::errc::not_enough_memory; + } - osd_printf_verbose("un7z: opened archive file %s\n", m_filename); + if (!m_archive_stream.file) + { + osd_file::ptr file; + std::error_condition const err = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_archive_stream.length); + if (err) + return err; + m_archive_stream.file = osd_file_read(std::move(file)); + osd_printf_verbose("un7z: opened archive file %s\n", m_filename); + } + else if (!m_archive_stream.length) + { + std::error_condition const err = m_archive_stream.file->length(m_archive_stream.length); + if (err) + { + osd_printf_verbose( + "un7z: error getting length of archive file %s (%s:%d %s)\n", + m_filename, err.category().name(), err.value(), err.message()); + return err; + } + } - CrcGenerateTable(); // FIXME: doesn't belong here - it should be called once statically + // TODO: coordinate this with other LZMA users in the codebase? + struct crc_table_generator { crc_table_generator() { CrcGenerateTable(); } }; + static crc_table_generator crc_table; SzArEx_Init(&m_db); m_inited = true; @@ -329,13 +369,13 @@ archive_file::error m7z_file_impl::initialize() switch (res) { case SZ_ERROR_UNSUPPORTED: return archive_file::error::UNSUPPORTED; - case SZ_ERROR_MEM: return archive_file::error::OUT_OF_MEMORY; + case SZ_ERROR_MEM: return std::errc::not_enough_memory; case SZ_ERROR_INPUT_EOF: return archive_file::error::FILE_TRUNCATED; - default: return archive_file::error::FILE_ERROR; + default: return std::errc::io_error; // TODO: better default error? } } - return archive_file::error::NONE; + return std::error_condition(); } @@ -344,33 +384,38 @@ archive_file::error m7z_file_impl::initialize() to the cache -------------------------------------------------*/ -void m7z_file_impl::close(ptr &&archive) +void m7z_file_impl::close(ptr &&archive) noexcept { - if (!archive) return; + // if the filename isn't empty, the implementation can be cached + if (archive && !archive->m_filename.empty()) + { + // close the open files + osd_printf_verbose("un7z: closing archive file %s and sending to cache\n", archive->m_filename); + archive->m_archive_stream.file.reset(); - // close the open files - osd_printf_verbose("un7z: closing archive file %s and sending to cache\n", archive->m_filename); - archive->m_archive_stream.osdfile.reset(); + // find the first nullptr entry in the cache + std::lock_guard<std::mutex> guard(s_cache_mutex); + std::size_t cachenum; + for (cachenum = 0; cachenum < s_cache.size(); cachenum++) + if (!s_cache[cachenum]) + break; - // find the first nullptr entry in the cache - std::lock_guard<std::mutex> guard(s_cache_mutex); - std::size_t cachenum; - for (cachenum = 0; cachenum < s_cache.size(); cachenum++) - if (!s_cache[cachenum]) - break; + // if no room left in the cache, free the bottommost entry + if (cachenum == s_cache.size()) + { + cachenum--; + osd_printf_verbose("un7z: removing %s from cache to make space\n", s_cache[cachenum]->m_filename); + s_cache[cachenum].reset(); + } - // if no room left in the cache, free the bottommost entry - if (cachenum == s_cache.size()) - { - cachenum--; - osd_printf_verbose("un7z: removing %s from cache to make space\n", s_cache[cachenum]->m_filename); - s_cache[cachenum].reset(); + // move everyone else down and place us at the top + for ( ; cachenum > 0; cachenum--) + s_cache[cachenum] = std::move(s_cache[cachenum - 1]); + s_cache[0] = std::move(archive); } - // move everyone else down and place us at the top - for ( ; cachenum > 0; cachenum--) - s_cache[cachenum] = std::move(s_cache[cachenum - 1]); - s_cache[0] = std::move(archive); + // make sure it's cleaned up + archive.reset(); } @@ -384,7 +429,7 @@ void m7z_file_impl::close(ptr &&archive) from a _7Z into the target buffer -------------------------------------------------*/ -archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length) +std::error_condition m7z_file_impl::decompress(void *buffer, std::size_t length) noexcept { // if we don't have enough buffer, error if (length < m_curr_length) @@ -394,15 +439,19 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length } // make sure the file is open.. - if (!m_archive_stream.osdfile) + if (!m_archive_stream.file) { - m_archive_stream.currfpos = 0; - osd_file::error const err = osd_file::open(m_filename, OPEN_FLAG_READ, m_archive_stream.osdfile, m_archive_stream.length); - if (err != osd_file::error::NONE) + m_archive_stream.currfpos = 0; // FIXME: should it really be changing the file pointer out from under LZMA? + osd_file::ptr file; + std::error_condition const err = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_archive_stream.length); + if (err) { - osd_printf_error("un7z: error reopening archive file %s (%d)\n", m_filename, int(err)); - return archive_file::error::FILE_ERROR; + osd_printf_error( + "un7z: error reopening archive file %s (%s:%d %s)\n", + m_filename, err.category().name(), err.value(), err.message()); + return err; } + m_archive_stream.file = osd_file_read(std::move(file)); osd_printf_verbose("un7z: reopened archive file %s\n", m_filename); } @@ -419,7 +468,7 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length switch (res) { case SZ_ERROR_UNSUPPORTED: return archive_file::error::UNSUPPORTED; - case SZ_ERROR_MEM: return archive_file::error::OUT_OF_MEMORY; + case SZ_ERROR_MEM: return std::errc::not_enough_memory; case SZ_ERROR_INPUT_EOF: return archive_file::error::FILE_TRUNCATED; default: return archive_file::error::DECOMPRESS_ERROR; } @@ -427,45 +476,64 @@ archive_file::error m7z_file_impl::decompress(void *buffer, std::uint32_t length // copy to destination buffer std::memcpy(buffer, m_out_buffer + offset, (std::min<std::size_t>)(length, out_size_processed)); - return archive_file::error::NONE; + return std::error_condition(); } int m7z_file_impl::search( int i, std::uint32_t search_crc, - const std::string &search_filename, + std::string_view search_filename, bool matchcrc, bool matchname, - bool partialpath) + bool partialpath) noexcept { - for ( ; i < m_db.NumFiles; i++) - { - make_utf8_name(i); - bool const is_dir(SzArEx_IsDir(&m_db, i)); - const std::uint64_t size(SzArEx_GetFileSize(&m_db, i)); - const std::uint32_t crc(m_db.CRCs.Vals[i]); - const bool crcmatch(SzBitArray_Check(m_db.CRCs.Defs, i) && (crc == search_crc)); - auto const partialoffset(m_utf8_buf.size() - 1 - search_filename.length()); - bool const partialpossible((m_utf8_buf.size() > (search_filename.length() + 1)) && (m_utf8_buf[partialoffset - 1] == '/')); - const bool namematch( - !core_stricmp(search_filename.c_str(), &m_utf8_buf[0]) || - (partialpath && partialpossible && !core_stricmp(search_filename.c_str(), &m_utf8_buf[partialoffset]))); - - const bool found = ((!matchcrc && !matchname) || !is_dir) && (!matchcrc || crcmatch) && (!matchname || namematch); - if (found) + try + { + for ( ; i < m_db.NumFiles; i++) { - m_curr_file_idx = i; - m_curr_is_dir = is_dir; - m_curr_name = &m_utf8_buf[0]; - m_curr_length = size; - set_curr_modified(); - m_curr_crc = crc; - - return i; + make_utf8_name(i); + bool const is_dir(SzArEx_IsDir(&m_db, i)); + const std::uint64_t size(SzArEx_GetFileSize(&m_db, i)); + const std::uint32_t crc(m_db.CRCs.Vals[i]); + + const bool crcmatch(SzBitArray_Check(m_db.CRCs.Defs, i) && (crc == search_crc)); + bool found; + if (!matchname) + { + found = !matchcrc || (crcmatch && !is_dir); + } + else + { + auto const partialoffset = m_utf8_buf.size() - search_filename.length(); + const bool namematch = + (search_filename.length() == m_utf8_buf.size()) && + (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_utf8_buf[0], search_filename.length())); + bool const partialmatch = + partialpath && + ((m_utf8_buf.size() > search_filename.length()) && (m_utf8_buf[partialoffset - 1] == '/')) && + (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_utf8_buf[partialoffset], search_filename.length())); + found = (!matchcrc || crcmatch) && (namematch || partialmatch); + } + + if (found) + { + // set the name first - resizing it can throw an exception, and we want the state to be consistent + m_curr_name.assign(m_utf8_buf.begin(), m_utf8_buf.end()); + m_curr_file_idx = i; + m_curr_is_dir = is_dir; + m_curr_length = size; + set_curr_modified(); + m_curr_crc = crc; + + return i; + } } } - + catch (...) + { + // allocation error handling name + } return -1; } @@ -475,14 +543,14 @@ void m7z_file_impl::make_utf8_name(int index) std::size_t len, out_pos; len = SzArEx_GetFileNameUtf16(&m_db, index, nullptr); - m_utf16_buf.resize((std::max<std::size_t>)(m_utf16_buf.size(), len)); + m_utf16_buf.resize(std::max<std::size_t>(m_utf16_buf.size(), len)); SzArEx_GetFileNameUtf16(&m_db, index, &m_utf16_buf[0]); - m_uchar_buf.resize((std::max<std::size_t>)(m_uchar_buf.size(), len)); + m_uchar_buf.resize(std::max<std::size_t>(m_uchar_buf.size(), len)); out_pos = 0; for (std::size_t in_pos = 0; in_pos < (len - 1); ) { - const int used = uchar_from_utf16(&m_uchar_buf[out_pos], (char16_t *)&m_utf16_buf[in_pos], len - in_pos); + const int used = uchar_from_utf16(&m_uchar_buf[out_pos], reinterpret_cast<char16_t const *>(&m_utf16_buf[in_pos]), len - in_pos); if (used < 0) { in_pos++; @@ -497,7 +565,7 @@ void m7z_file_impl::make_utf8_name(int index) } len = out_pos; - m_utf8_buf.resize((std::max<std::size_t>)(m_utf8_buf.size(), 4 * len + 1)); + m_utf8_buf.resize((std::max<std::size_t>)(m_utf8_buf.size(), 4 * len)); out_pos = 0; for (std::size_t in_pos = 0; in_pos < len; in_pos++) { @@ -508,30 +576,35 @@ void m7z_file_impl::make_utf8_name(int index) out_pos += produced; assert(out_pos < m_utf8_buf.size()); } - m_utf8_buf[out_pos++] = '\0'; m_utf8_buf.resize(out_pos); } -void m7z_file_impl::set_curr_modified() +void m7z_file_impl::set_curr_modified() noexcept { if (SzBitWithVals_Check(&m_db.MTime, m_curr_file_idx)) { CNtfsFileTime const &file_time(m_db.MTime.Vals[m_curr_file_idx]); - auto ticks = ntfs_duration_from_filetime(file_time.High, file_time.Low); - m_curr_modified = system_clock_time_point_from_ntfs_duration(ticks); - } - else - { - // FIXME: what do we do about a lack of time? + try + { + auto ticks = ntfs_duration_from_filetime(file_time.High, file_time.Low); + m_curr_modified = system_clock_time_point_from_ntfs_duration(ticks); + return; + } + catch (...) + { + } } + + // no modification time available, or out-of-range exception + m_curr_modified = std::chrono::system_clock::from_time_t(std::time_t(0)); } } // anonymous namespace -archive_file::error archive_file::open_7z(const std::string &filename, ptr &result) +std::error_condition archive_file::open_7z(std::string_view filename, ptr &result) noexcept { // ensure we start with a nullptr result result.reset(); @@ -542,21 +615,49 @@ archive_file::error archive_file::open_7z(const std::string &filename, ptr &resu if (!newimpl) { // allocate memory for the 7z file structure - try { newimpl = std::make_unique<m7z_file_impl>(filename); } - catch (...) { return error::OUT_OF_MEMORY; } - error const err = newimpl->initialize(); - if (err != error::NONE) return err; + try { newimpl = std::make_unique<m7z_file_impl>(std::string(filename)); } + catch (...) { return std::errc::not_enough_memory; } + auto const err = newimpl->initialize(); + if (err) + return err; } - try + // allocate the archive API wrapper + result.reset(new (std::nothrow) m7z_file_wrapper(std::move(newimpl))); + if (result) { - result = std::make_unique<m7z_file_wrapper>(std::move(newimpl)); - return error::NONE; + return std::error_condition(); } - catch (...) + else + { + m7z_file_impl::close(std::move(newimpl)); + return std::errc::not_enough_memory; + } +} + +std::error_condition archive_file::open_7z(random_read::ptr &&file, ptr &result) noexcept +{ + // ensure we start with a nullptr result + result.reset(); + + // allocate memory for the zip_file structure + m7z_file_impl::ptr newimpl(new (std::nothrow) m7z_file_impl(std::move(file))); + if (!newimpl) + return std::errc::not_enough_memory; + auto const err = newimpl->initialize(); + if (err) + return err; + + // allocate the archive API wrapper + result.reset(new (std::nothrow) m7z_file_wrapper(std::move(newimpl))); + if (result) + { + return std::error_condition(); + } + else { m7z_file_impl::close(std::move(newimpl)); - return error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -566,7 +667,7 @@ archive_file::error archive_file::open_7z(const std::string &filename, ptr &resu cache and free all memory -------------------------------------------------*/ -void m7z_file_cache_clear() +void m7z_file_cache_clear() noexcept { // This is a trampoline called from unzip.cpp to avoid the need to have the zip and 7zip code in one file m7z_file_impl::cache_clear(); diff --git a/src/lib/util/unzip.cpp b/src/lib/util/unzip.cpp index a275cc7df06..d7df8fa5ce9 100644 --- a/src/lib/util/unzip.cpp +++ b/src/lib/util/unzip.cpp @@ -12,9 +12,11 @@ #include "corestr.h" #include "hashing.h" +#include "ioprocs.h" +#include "timeconv.h" + #include "osdcore.h" #include "osdfile.h" -#include "timeconv.h" #include "lzma/C/LzmaDec.h" @@ -23,6 +25,7 @@ #include <algorithm> #include <array> #include <cassert> +#include <cerrno> #include <chrono> #include <cstring> #include <cstdlib> @@ -34,31 +37,55 @@ namespace util { + namespace { + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ +class archive_category_impl : public std::error_category +{ +public: + virtual char const *name() const noexcept override { return "archive"; } + + virtual std::string message(int condition) const override + { + using namespace std::literals; + static std::string_view const s_messages[] = { + "No error"sv, + "Bad archive signature"sv, + "Decompression error"sv, + "Archive file truncated"sv, + "Archive file corrupt"sv, + "Archive file uses unsupported features"sv, + "Buffer too small for data"sv }; + if ((0 <= condition) && (std::size(s_messages) > condition)) + return std::string(s_messages[condition]); + else + return "Unknown error"s; + } +}; + + class zip_file_impl { public: - typedef std::unique_ptr<zip_file_impl> ptr; - - zip_file_impl(const std::string &filename) - : m_filename(filename) - , m_file() - , m_length(0) - , m_ecd() - , m_cd() - , m_cd_pos(0) - , m_header() - , m_curr_is_dir(false) - , m_buffer() + using ptr = std::unique_ptr<zip_file_impl>; + + zip_file_impl(std::string &&filename) noexcept + : m_filename(std::move(filename)) { std::fill(m_buffer.begin(), m_buffer.end(), 0); } - static ptr find_cached(const std::string &filename) + zip_file_impl(random_read::ptr &&file) noexcept + : zip_file_impl(std::string()) + { + m_file = std::move(file); + } + + static ptr find_cached(std::string_view filename) noexcept { std::lock_guard<std::mutex> guard(s_cache_mutex); for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++) @@ -66,27 +93,31 @@ public: // if we have a valid entry and it matches our filename, use it and remove from the cache if (s_cache[cachenum] && (filename == s_cache[cachenum]->m_filename)) { + using std::swap; ptr result; - std::swap(s_cache[cachenum], result); + swap(s_cache[cachenum], result); osd_printf_verbose("unzip: found %s in cache\n", filename); return result; } } return ptr(); } - static void close(ptr &&zip); - static void cache_clear() + + static void close(ptr &&zip) noexcept; + + static void cache_clear() noexcept { // clear call cache entries std::lock_guard<std::mutex> guard(s_cache_mutex); - for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { } + for (auto &cached : s_cache) + cached.reset(); } - archive_file::error initialize() + std::error_condition initialize() noexcept { // read ecd data auto const ziperr = read_ecd(); - if (ziperr != archive_file::error::NONE) + if (ziperr) return ziperr; // verify that we can work with this zipfile (no disk spanning allowed) @@ -111,7 +142,7 @@ public: catch (...) { osd_printf_error("unzip: %s failed to allocate memory for central directory\n", m_filename); - return archive_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } // read the central directory @@ -119,13 +150,15 @@ public: std::size_t cd_offs(0); while (cd_remaining) { - std::uint32_t const chunk(std::uint32_t((std::min<std::uint64_t>)(std::numeric_limits<std::uint32_t>::max(), cd_remaining))); - std::uint32_t read_length(0); - auto const filerr = m_file->read(&m_cd[cd_offs], m_ecd.cd_start_disk_offset + cd_offs, chunk, read_length); - if (filerr != osd_file::error::NONE) + std::size_t const chunk(std::size_t(std::min<std::uint64_t>(std::numeric_limits<std::size_t>::max(), cd_remaining))); + std::size_t read_length(0); + std::error_condition const filerr = m_file->read_at(m_ecd.cd_start_disk_offset + cd_offs, &m_cd[cd_offs], chunk, read_length); + if (filerr) { - osd_printf_error("unzip: %s error reading central directory (%d)\n", m_filename, int(filerr)); - return archive_file::error::FILE_ERROR; + osd_printf_error( + "unzip: %s error reading central directory (%s:%d %s)\n", + m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } if (!read_length) { @@ -137,39 +170,45 @@ public: } osd_printf_verbose("unzip: read %s central directory\n", m_filename); - return archive_file::error::NONE; + return std::error_condition(); } - int first_file() + int first_file() noexcept { m_cd_pos = 0; - return search(0, std::string(), false, false, false); + return search(0, std::string_view(), false, false, false); } - int next_file() + + int next_file() noexcept { - return search(0, std::string(), false, false, false); + return search(0, std::string_view(), false, false, false); } - int search(std::uint32_t crc) + int search(std::uint32_t crc) noexcept { m_cd_pos = 0; - return search(crc, std::string(), true, false, false); + return search(crc, std::string_view(), true, false, false); } - int search(const std::string &filename, bool partialpath) + + int search(std::string_view filename, bool partialpath) noexcept { m_cd_pos = 0; return search(0, filename, false, true, partialpath); } - int search(std::uint32_t crc, const std::string &filename, bool partialpath) + + int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept { m_cd_pos = 0; return search(crc, filename, true, true, partialpath); } - bool current_is_directory() const { return m_curr_is_dir; } - const std::string ¤t_name() const { return m_header.file_name; } - std::uint64_t current_uncompressed_length() const { return m_header.uncompressed_length; } - std::chrono::system_clock::time_point current_last_modified() const + bool current_is_directory() const noexcept { return m_curr_is_dir; } + + const std::string ¤t_name() const noexcept { return m_header.file_name; } + + std::uint64_t current_uncompressed_length() const noexcept { return m_header.uncompressed_length; } + + std::chrono::system_clock::time_point current_last_modified() const noexcept { if (!m_header.modified_cached) { @@ -178,9 +217,10 @@ public: } return m_header.modified; } - std::uint32_t current_crc() const { return m_header.crc; } - archive_file::error decompress(void *buffer, std::uint32_t length); + std::uint32_t current_crc() const noexcept { return m_header.crc; } + + std::error_condition decompress(void *buffer, std::size_t length) noexcept; private: zip_file_impl(const zip_file_impl &) = delete; @@ -188,28 +228,43 @@ private: zip_file_impl &operator=(const zip_file_impl &) = delete; zip_file_impl &operator=(zip_file_impl &&) = delete; - int search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname, bool partialpath); + int search(std::uint32_t search_crc, std::string_view search_filename, bool matchcrc, bool matchname, bool partialpath) noexcept; - archive_file::error reopen() + std::error_condition reopen() noexcept { if (!m_file) { - auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, m_file, m_length); - if (filerr != osd_file::error::NONE) + osd_file::ptr file; + auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, file, m_length); + if (filerr) { // this would spam every time it looks for a non-existent archive, which is a lot - //osd_printf_error("unzip: error reopening archive file %s (%d)\n", m_filename, int(filerr)); - return archive_file::error::FILE_ERROR; + //osd_printf_error("unzip: error reopening archive file %s (%s:%d %s)\n", m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } - else + m_file = osd_file_read(std::move(file)); + if (!m_file) { - osd_printf_verbose("unzip: opened archive file %s\n", m_filename); + osd_printf_error("unzip: not enough memory to open archive file %s\n", m_filename); + return std::errc::not_enough_memory; } + osd_printf_verbose("unzip: opened archive file %s\n", m_filename); } - return archive_file::error::NONE; + else if (!m_length) + { + auto const filerr = m_file->length(m_length); + if (filerr) + { + osd_printf_verbose( + "unzip: error getting length of archive file %s (%s:%d %s)\n", + m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; + } + } + return std::error_condition(); } - static std::chrono::system_clock::time_point decode_dos_time(std::uint16_t date, std::uint16_t time) + static std::chrono::system_clock::time_point decode_dos_time(std::uint16_t date, std::uint16_t time) noexcept { // FIXME: work out why this doesn't always work // negative tm_isdst should automatically determine whether DST is in effect for the date, @@ -228,16 +283,22 @@ private: } // ZIP file parsing - archive_file::error read_ecd(); - archive_file::error get_compressed_data_offset(std::uint64_t &offset); + std::error_condition read_ecd() noexcept; + std::error_condition get_compressed_data_offset(std::uint64_t &offset) noexcept; // decompression interfaces - archive_file::error decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length); - archive_file::error decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length); - archive_file::error decompress_data_type_14(std::uint64_t offset, void *buffer, std::uint32_t length); + std::error_condition decompress_data_type_0(std::uint64_t offset, void *buffer, std::size_t length) noexcept; + std::error_condition decompress_data_type_8(std::uint64_t offset, void *buffer, std::size_t length) noexcept; + std::error_condition decompress_data_type_14(std::uint64_t offset, void *buffer, std::size_t length) noexcept; struct file_header { + file_header() noexcept { } + file_header(file_header const &) = default; + file_header(file_header &&) noexcept = default; + file_header &operator=(file_header const &) = default; + file_header &operator=(file_header &&) noexcept = default; + std::uint16_t version_created; // version made by std::uint16_t version_needed; // version needed to extract std::uint16_t bit_flag; // general purpose bit flag @@ -271,15 +332,15 @@ private: static std::mutex s_cache_mutex; const std::string m_filename; // copy of ZIP filename (for caching) - osd_file::ptr m_file; // OSD file handle - std::uint64_t m_length; // length of zip file + random_read::ptr m_file; // file handle + std::uint64_t m_length = 0; // length of zip file ecd m_ecd; // end of central directory std::vector<std::uint8_t> m_cd; // central directory raw data - std::uint32_t m_cd_pos; // position in central directory + std::uint32_t m_cd_pos = 0; // position in central directory file_header m_header; // current file header - bool m_curr_is_dir; // current file is directory + bool m_curr_is_dir = false; // current file is directory std::array<std::uint8_t, DECOMPRESS_BUFSIZE> m_buffer; // buffer for decompression }; @@ -288,32 +349,32 @@ private: class zip_file_wrapper : public archive_file { public: - zip_file_wrapper(zip_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); } + zip_file_wrapper(zip_file_impl::ptr &&impl) noexcept : m_impl(std::move(impl)) { assert(m_impl); } virtual ~zip_file_wrapper() { zip_file_impl::close(std::move(m_impl)); } - virtual int first_file() override { return m_impl->first_file(); } - virtual int next_file() override { return m_impl->next_file(); } + virtual int first_file() noexcept override { return m_impl->first_file(); } + virtual int next_file() noexcept override { return m_impl->next_file(); } - virtual int search(std::uint32_t crc) override + virtual int search(std::uint32_t crc) noexcept override { return m_impl->search(crc); } - virtual int search(const std::string &filename, bool partialpath) override + virtual int search(std::string_view filename, bool partialpath) noexcept override { return m_impl->search(filename, partialpath); } - virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) override + virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept override { return m_impl->search(crc, filename, partialpath); } - virtual bool current_is_directory() const override { return m_impl->current_is_directory(); } - virtual const std::string ¤t_name() const override { return m_impl->current_name(); } - virtual std::uint64_t current_uncompressed_length() const override { return m_impl->current_uncompressed_length(); } - virtual std::chrono::system_clock::time_point current_last_modified() const override { return m_impl->current_last_modified(); } - virtual std::uint32_t current_crc() const override { return m_impl->current_crc(); } + virtual bool current_is_directory() const noexcept override { return m_impl->current_is_directory(); } + virtual const std::string ¤t_name() const noexcept override { return m_impl->current_name(); } + virtual std::uint64_t current_uncompressed_length() const noexcept override { return m_impl->current_uncompressed_length(); } + virtual std::chrono::system_clock::time_point current_last_modified() const noexcept override { return m_impl->current_last_modified(); } + virtual std::uint32_t current_crc() const noexcept override { return m_impl->current_crc(); } - virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); } + virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept override { return m_impl->decompress(buffer, length); } private: zip_file_impl::ptr m_impl; @@ -323,19 +384,19 @@ private: class reader_base { protected: - reader_base(void const *buf) : m_buffer(reinterpret_cast<std::uint8_t const *>(buf)) { } + reader_base(void const *buf) noexcept : m_buffer(reinterpret_cast<std::uint8_t const *>(buf)) { } - std::uint8_t read_byte(std::size_t offs) const + std::uint8_t read_byte(std::size_t offs) const noexcept { return m_buffer[offs]; } - std::uint16_t read_word(std::size_t offs) const + std::uint16_t read_word(std::size_t offs) const noexcept { return (std::uint16_t(m_buffer[offs + 1]) << 8) | (std::uint16_t(m_buffer[offs + 0]) << 0); } - std::uint32_t read_dword(std::size_t offs) const + std::uint32_t read_dword(std::size_t offs) const noexcept { return (std::uint32_t(m_buffer[offs + 3]) << 24) | @@ -343,7 +404,7 @@ protected: (std::uint32_t(m_buffer[offs + 1]) << 8) | (std::uint32_t(m_buffer[offs + 0]) << 0); } - std::uint64_t read_qword(std::size_t offs) const + std::uint64_t read_qword(std::size_t offs) const noexcept { return (std::uint64_t(m_buffer[offs + 7]) << 56) | @@ -371,17 +432,17 @@ protected: class extra_field_reader : private reader_base { public: - extra_field_reader(void const *buf, std::size_t len) : reader_base(buf), m_length(len) { } + extra_field_reader(void const *buf, std::size_t len) noexcept : reader_base(buf), m_length(len) { } - std::uint16_t header_id() const { return read_word(0x00); } - std::uint16_t data_size() const { return read_word(0x02); } - void const * data() const { return m_buffer + 0x04; } - extra_field_reader next() const { return extra_field_reader(m_buffer + total_length(), m_length - total_length()); } + std::uint16_t header_id() const noexcept { return read_word(0x00); } + std::uint16_t data_size() const noexcept { return read_word(0x02); } + void const * data() const noexcept { return m_buffer + 0x04; } + extra_field_reader next() const noexcept { return extra_field_reader(m_buffer + total_length(), m_length - total_length()); } - bool length_sufficient() const { return (m_length >= minimum_length()) && (m_length >= total_length()); } + bool length_sufficient() const noexcept { return (m_length >= minimum_length()) && (m_length >= total_length()); } - std::size_t total_length() const { return minimum_length() + data_size(); } - static std::size_t minimum_length() { return 0x04; } + std::size_t total_length() const noexcept { return minimum_length() + data_size(); } + static constexpr std::size_t minimum_length() { return 0x04; } private: std::size_t m_length; @@ -391,131 +452,131 @@ private: class local_file_header_reader : private reader_base { public: - local_file_header_reader(void const *buf) : reader_base(buf) { } - - std::uint32_t signature() const { return read_dword(0x00); } - std::uint8_t version_needed() const { return m_buffer[0x04]; } - std::uint8_t os_needed() const { return m_buffer[0x05]; } - std::uint16_t general_flag() const { return read_word(0x06); } - std::uint16_t compression_method() const { return read_word(0x08); } - std::uint16_t modified_time() const { return read_word(0x0a); } - std::uint16_t modified_date() const { return read_word(0x0c); } - std::uint32_t crc32() const { return read_dword(0x0e); } - std::uint32_t compressed_size() const { return read_dword(0x12); } - std::uint32_t uncompressed_size() const { return read_dword(0x16); } - std::uint16_t file_name_length() const { return read_word(0x1a); } - std::uint16_t extra_field_length() const { return read_word(0x1c); } + local_file_header_reader(void const *buf) noexcept : reader_base(buf) { } + + std::uint32_t signature() const noexcept { return read_dword(0x00); } + std::uint8_t version_needed() const noexcept { return m_buffer[0x04]; } + std::uint8_t os_needed() const noexcept { return m_buffer[0x05]; } + std::uint16_t general_flag() const noexcept { return read_word(0x06); } + std::uint16_t compression_method() const noexcept { return read_word(0x08); } + std::uint16_t modified_time() const noexcept { return read_word(0x0a); } + std::uint16_t modified_date() const noexcept { return read_word(0x0c); } + std::uint32_t crc32() const noexcept { return read_dword(0x0e); } + std::uint32_t compressed_size() const noexcept { return read_dword(0x12); } + std::uint32_t uncompressed_size() const noexcept { return read_dword(0x16); } + std::uint16_t file_name_length() const noexcept { return read_word(0x1a); } + std::uint16_t extra_field_length() const noexcept { return read_word(0x1c); } std::string file_name() const { return read_string(0x1e, file_name_length()); } void file_name(std::string &result) const { read_string(result, 0x1e, file_name_length()); } - extra_field_reader extra_field() const { return extra_field_reader(m_buffer + 0x1e + file_name_length(), extra_field_length()); } + extra_field_reader extra_field() const noexcept { return extra_field_reader(m_buffer + 0x1e + file_name_length(), extra_field_length()); } - bool signature_correct() const { return signature() == 0x04034b50; } + bool signature_correct() const noexcept { return signature() == 0x04034b50; } - std::size_t total_length() const { return minimum_length() + file_name_length() + extra_field_length(); } - static std::size_t minimum_length() { return 0x1e; } + std::size_t total_length() const noexcept { return minimum_length() + file_name_length() + extra_field_length(); } + static constexpr std::size_t minimum_length() { return 0x1e; } }; class central_dir_entry_reader : private reader_base { public: - central_dir_entry_reader(void const *buf) : reader_base(buf) { } - - std::uint32_t signature() const { return read_dword(0x00); } - std::uint8_t version_created() const { return m_buffer[0x04]; } - std::uint8_t os_created() const { return m_buffer[0x05]; } - std::uint8_t version_needed() const { return m_buffer[0x06]; } - std::uint8_t os_needed() const { return m_buffer[0x07]; } - std::uint16_t general_flag() const { return read_word(0x08); } - std::uint16_t compression_method() const { return read_word(0x0a); } - std::uint16_t modified_time() const { return read_word(0x0c); } - std::uint16_t modified_date() const { return read_word(0x0e); } - std::uint32_t crc32() const { return read_dword(0x10); } - std::uint32_t compressed_size() const { return read_dword(0x14); } - std::uint32_t uncompressed_size() const { return read_dword(0x18); } - std::uint16_t file_name_length() const { return read_word(0x1c); } - std::uint16_t extra_field_length() const { return read_word(0x1e); } - std::uint16_t file_comment_length() const { return read_word(0x20); } - std::uint16_t start_disk() const { return read_word(0x22); } - std::uint16_t int_file_attr() const { return read_word(0x24); } - std::uint32_t ext_file_attr() const { return read_dword(0x26); } - std::uint32_t header_offset() const { return read_dword(0x2a); } + central_dir_entry_reader(void const *buf) noexcept : reader_base(buf) { } + + std::uint32_t signature() const noexcept { return read_dword(0x00); } + std::uint8_t version_created() const noexcept { return m_buffer[0x04]; } + std::uint8_t os_created() const noexcept { return m_buffer[0x05]; } + std::uint8_t version_needed() const noexcept { return m_buffer[0x06]; } + std::uint8_t os_needed() const noexcept { return m_buffer[0x07]; } + std::uint16_t general_flag() const noexcept { return read_word(0x08); } + std::uint16_t compression_method() const noexcept { return read_word(0x0a); } + std::uint16_t modified_time() const noexcept { return read_word(0x0c); } + std::uint16_t modified_date() const noexcept { return read_word(0x0e); } + std::uint32_t crc32() const noexcept { return read_dword(0x10); } + std::uint32_t compressed_size() const noexcept { return read_dword(0x14); } + std::uint32_t uncompressed_size() const noexcept { return read_dword(0x18); } + std::uint16_t file_name_length() const noexcept { return read_word(0x1c); } + std::uint16_t extra_field_length() const noexcept { return read_word(0x1e); } + std::uint16_t file_comment_length() const noexcept { return read_word(0x20); } + std::uint16_t start_disk() const noexcept { return read_word(0x22); } + std::uint16_t int_file_attr() const noexcept { return read_word(0x24); } + std::uint32_t ext_file_attr() const noexcept { return read_dword(0x26); } + std::uint32_t header_offset() const noexcept { return read_dword(0x2a); } std::string file_name() const { return read_string(0x2e, file_name_length()); } void file_name(std::string &result) const { read_string(result, 0x2e, file_name_length()); } - extra_field_reader extra_field() const { return extra_field_reader(m_buffer + 0x2e + file_name_length(), extra_field_length()); } + extra_field_reader extra_field() const noexcept { return extra_field_reader(m_buffer + 0x2e + file_name_length(), extra_field_length()); } std::string file_comment() const { return read_string(0x2e + file_name_length() + extra_field_length(), file_comment_length()); } void file_comment(std::string &result) const { read_string(result, 0x2e + file_name_length() + extra_field_length(), file_comment_length()); } - bool signature_correct() const { return signature() == 0x02014b50; } + bool signature_correct() const noexcept { return signature() == 0x02014b50; } - std::size_t total_length() const { return minimum_length() + file_name_length() + extra_field_length() + file_comment_length(); } - static std::size_t minimum_length() { return 0x2e; } + std::size_t total_length() const noexcept { return minimum_length() + file_name_length() + extra_field_length() + file_comment_length(); } + static constexpr std::size_t minimum_length() { return 0x2e; } }; class ecd64_reader : private reader_base { public: - ecd64_reader(void const *buf) : reader_base(buf) { } - - std::uint32_t signature() const { return read_dword(0x00); } - std::uint64_t ecd64_size() const { return read_qword(0x04); } - std::uint8_t version_created() const { return m_buffer[0x0c]; } - std::uint8_t os_created() const { return m_buffer[0x0d]; } - std::uint8_t version_needed() const { return m_buffer[0x0e]; } - std::uint8_t os_needed() const { return m_buffer[0x0f]; } - std::uint32_t this_disk_no() const { return read_dword(0x10); } - std::uint32_t dir_start_disk() const { return read_dword(0x14); } - std::uint64_t dir_disk_entries() const { return read_qword(0x18); } - std::uint64_t dir_total_entries() const { return read_qword(0x20); } - std::uint64_t dir_size() const { return read_qword(0x28); } - std::uint64_t dir_offset() const { return read_qword(0x30); } - void const * extensible_data() const { return m_buffer + 0x38; } - - bool signature_correct() const { return signature() == 0x06064b50; } - - std::size_t total_length() const { return 0x0c + ecd64_size(); } - static std::size_t minimum_length() { return 0x38; } + ecd64_reader(void const *buf) noexcept : reader_base(buf) { } + + std::uint32_t signature() const noexcept { return read_dword(0x00); } + std::uint64_t ecd64_size() const noexcept { return read_qword(0x04); } + std::uint8_t version_created() const noexcept { return m_buffer[0x0c]; } + std::uint8_t os_created() const noexcept { return m_buffer[0x0d]; } + std::uint8_t version_needed() const noexcept { return m_buffer[0x0e]; } + std::uint8_t os_needed() const noexcept { return m_buffer[0x0f]; } + std::uint32_t this_disk_no() const noexcept { return read_dword(0x10); } + std::uint32_t dir_start_disk() const noexcept { return read_dword(0x14); } + std::uint64_t dir_disk_entries() const noexcept { return read_qword(0x18); } + std::uint64_t dir_total_entries() const noexcept { return read_qword(0x20); } + std::uint64_t dir_size() const noexcept { return read_qword(0x28); } + std::uint64_t dir_offset() const noexcept { return read_qword(0x30); } + void const * extensible_data() const noexcept { return m_buffer + 0x38; } + + bool signature_correct() const noexcept { return signature() == 0x06064b50; } + + std::size_t total_length() const noexcept { return 0x0c + ecd64_size(); } + static constexpr std::size_t minimum_length() { return 0x38; } }; class ecd64_locator_reader : private reader_base { public: - ecd64_locator_reader(void const *buf) : reader_base(buf) { } + ecd64_locator_reader(void const *buf) noexcept : reader_base(buf) { } - std::uint32_t signature() const { return read_dword(0x00); } - std::uint32_t ecd64_disk() const { return read_dword(0x04); } - std::uint64_t ecd64_offset() const { return read_qword(0x08); } - std::uint32_t total_disks() const { return read_dword(0x10); } + std::uint32_t signature() const noexcept { return read_dword(0x00); } + std::uint32_t ecd64_disk() const noexcept { return read_dword(0x04); } + std::uint64_t ecd64_offset() const noexcept { return read_qword(0x08); } + std::uint32_t total_disks() const noexcept { return read_dword(0x10); } - bool signature_correct() const { return signature() == 0x07064b50; } + bool signature_correct() const noexcept { return signature() == 0x07064b50; } - std::size_t total_length() const { return minimum_length(); } - static std::size_t minimum_length() { return 0x14; } + std::size_t total_length() const noexcept { return minimum_length(); } + static constexpr std::size_t minimum_length() { return 0x14; } }; class ecd_reader : private reader_base { public: - ecd_reader(void const *buf) : reader_base(buf) { } - - std::uint32_t signature() const { return read_dword(0x00); } - std::uint16_t this_disk_no() const { return read_word(0x04); } - std::uint16_t dir_start_disk() const { return read_word(0x06); } - std::uint16_t dir_disk_entries() const { return read_word(0x08); } - std::uint16_t dir_total_entries() const { return read_word(0x0a); } - std::uint32_t dir_size() const { return read_dword(0x0c); } - std::uint32_t dir_offset() const { return read_dword(0x10); } - std::uint16_t comment_length() const { return read_word(0x14); } + ecd_reader(void const *buf) noexcept : reader_base(buf) { } + + std::uint32_t signature() const noexcept { return read_dword(0x00); } + std::uint16_t this_disk_no() const noexcept { return read_word(0x04); } + std::uint16_t dir_start_disk() const noexcept { return read_word(0x06); } + std::uint16_t dir_disk_entries() const noexcept { return read_word(0x08); } + std::uint16_t dir_total_entries() const noexcept { return read_word(0x0a); } + std::uint32_t dir_size() const noexcept { return read_dword(0x0c); } + std::uint32_t dir_offset() const noexcept { return read_dword(0x10); } + std::uint16_t comment_length() const noexcept { return read_word(0x14); } std::string comment() const { return read_string(0x16, comment_length()); } void comment(std::string &result) const { read_string(result, 0x16, comment_length()); } - bool signature_correct() const { return signature() == 0x06054b50; } + bool signature_correct() const noexcept { return signature() == 0x06054b50; } - std::size_t total_length() const { return minimum_length() + comment_length(); } - static std::size_t minimum_length() { return 0x16; } + std::size_t total_length() const noexcept { return minimum_length() + comment_length(); } + static constexpr std::size_t minimum_length() { return 0x16; } }; @@ -525,7 +586,7 @@ public: template <typename T> zip64_ext_info_reader( T const &header, - extra_field_reader const &field) + extra_field_reader const &field) noexcept : reader_base(field.data()) , m_uncompressed_size(header.uncompressed_size()) , m_compressed_size(header.compressed_size()) @@ -538,13 +599,13 @@ public: { } - std::uint64_t uncompressed_size() const { return ~m_uncompressed_size ? m_uncompressed_size : read_qword(0x00); } - std::uint64_t compressed_size() const { return ~m_compressed_size ? m_compressed_size : read_qword(m_offs_compressed_size); } - std::uint64_t header_offset() const { return ~m_header_offset ? m_header_offset : read_qword(m_offs_header_offset); } - std::uint32_t start_disk() const { return ~m_start_disk ? m_start_disk : read_dword(m_offs_start_disk); } + std::uint64_t uncompressed_size() const noexcept { return ~m_uncompressed_size ? m_uncompressed_size : read_qword(0x00); } + std::uint64_t compressed_size() const noexcept { return ~m_compressed_size ? m_compressed_size : read_qword(m_offs_compressed_size); } + std::uint64_t header_offset() const noexcept { return ~m_header_offset ? m_header_offset : read_qword(m_offs_header_offset); } + std::uint32_t start_disk() const noexcept { return ~m_start_disk ? m_start_disk : read_dword(m_offs_start_disk); } - std::size_t total_length() const { return minimum_length() + m_offs_end; } - static std::size_t minimum_length() { return 0x00; } + std::size_t total_length() const noexcept { return minimum_length() + m_offs_end; } + static constexpr std::size_t minimum_length() { return 0x00; } private: std::uint32_t m_uncompressed_size; @@ -562,15 +623,15 @@ private: class utf8_path_reader : private reader_base { public: - utf8_path_reader(extra_field_reader const &field) : reader_base(field.data()), m_length(field.data_size()) { } + utf8_path_reader(extra_field_reader const &field) noexcept : reader_base(field.data()), m_length(field.data_size()) { } - std::uint8_t version() const { return m_buffer[0]; } - std::uint32_t name_crc32() const { return read_dword(0x01); } + std::uint8_t version() const noexcept { return m_buffer[0]; } + std::uint32_t name_crc32() const noexcept { return read_dword(0x01); } std::string unicode_name() const { return read_string(0x05, m_length - 0x05); } void unicode_name(std::string &result) const { return read_string(result, 0x05, m_length - 0x05); } - std::size_t total_length() const { return m_length; } - static std::size_t minimum_length() { return 0x05; } + std::size_t total_length() const noexcept { return m_length; } + static constexpr std::size_t minimum_length() { return 0x05; } private: std::size_t m_length; @@ -580,17 +641,17 @@ private: class ntfs_tag_reader : private reader_base { public: - ntfs_tag_reader(void const *buf, std::size_t len) : reader_base(buf), m_length(len) { } + ntfs_tag_reader(void const *buf, std::size_t len) noexcept : reader_base(buf), m_length(len) { } - std::uint16_t tag() const { return read_word(0x00); } - std::uint16_t size() const { return read_word(0x02); } - void const * data() const { return m_buffer + 0x04; } - ntfs_tag_reader next() const { return ntfs_tag_reader(m_buffer + total_length(), m_length - total_length()); } + std::uint16_t tag() const noexcept { return read_word(0x00); } + std::uint16_t size() const noexcept { return read_word(0x02); } + void const * data() const noexcept { return m_buffer + 0x04; } + ntfs_tag_reader next() const noexcept { return ntfs_tag_reader(m_buffer + total_length(), m_length - total_length()); } - bool length_sufficient() const { return (m_length >= minimum_length()) && (m_length >= total_length()); } + bool length_sufficient() const noexcept { return (m_length >= minimum_length()) && (m_length >= total_length()); } - std::size_t total_length() const { return minimum_length() + size(); } - static std::size_t minimum_length() { return 0x04; } + std::size_t total_length() const noexcept { return minimum_length() + size(); } + static constexpr std::size_t minimum_length() { return 0x04; } private: std::size_t m_length; @@ -600,13 +661,13 @@ private: class ntfs_reader : private reader_base { public: - ntfs_reader(extra_field_reader const &field) : reader_base(field.data()), m_length(field.data_size()) { } + ntfs_reader(extra_field_reader const &field) noexcept : reader_base(field.data()), m_length(field.data_size()) { } - std::uint32_t reserved() const { return read_dword(0x00); } - ntfs_tag_reader tag1() const { return ntfs_tag_reader(m_buffer + 0x04, m_length - 4); } + std::uint32_t reserved() const noexcept { return read_dword(0x00); } + ntfs_tag_reader tag1() const noexcept { return ntfs_tag_reader(m_buffer + 0x04, m_length - 4); } - std::size_t total_length() const { return m_length; } - static std::size_t minimum_length() { return 0x08; } + std::size_t total_length() const noexcept { return m_length; } + static constexpr std::size_t minimum_length() { return 0x08; } private: std::size_t m_length; @@ -616,14 +677,14 @@ private: class ntfs_times_reader : private reader_base { public: - ntfs_times_reader(ntfs_tag_reader const &tag) : reader_base(tag.data()) { } + ntfs_times_reader(ntfs_tag_reader const &tag) noexcept : reader_base(tag.data()) { } - std::uint64_t mtime() const { return read_qword(0x00); } - std::uint64_t atime() const { return read_qword(0x08); } - std::uint64_t ctime() const { return read_qword(0x10); } + std::uint64_t mtime() const noexcept { return read_qword(0x00); } + std::uint64_t atime() const noexcept { return read_qword(0x08); } + std::uint64_t ctime() const noexcept { return read_qword(0x10); } - std::size_t total_length() const { return minimum_length(); } - static std::size_t minimum_length() { return 0x18; } + std::size_t total_length() const noexcept { return minimum_length(); } + static constexpr std::size_t minimum_length() { return 0x18; } }; @@ -632,16 +693,16 @@ class general_flag_reader public: general_flag_reader(std::uint16_t val) : m_value(val) { } - bool encrypted() const { return bool(m_value & 0x0001); } - bool implode_8k_dict() const { return bool(m_value & 0x0002); } - bool implode_3_trees() const { return bool(m_value & 0x0004); } - unsigned deflate_option() const { return unsigned((m_value >> 1) & 0x0003); } - bool lzma_eos_mark() const { return bool(m_value & 0x0002); } - bool use_descriptor() const { return bool(m_value & 0x0008); } - bool patch_data() const { return bool(m_value & 0x0020); } - bool strong_encryption() const { return bool(m_value & 0x0040); } - bool utf8_encoding() const { return bool(m_value & 0x0800); } - bool directory_encryption() const { return bool(m_value & 0x2000); } + bool encrypted() const noexcept { return bool(m_value & 0x0001); } + bool implode_8k_dict() const noexcept { return bool(m_value & 0x0002); } + bool implode_3_trees() const noexcept { return bool(m_value & 0x0004); } + unsigned deflate_option() const noexcept { return unsigned((m_value >> 1) & 0x0003); } + bool lzma_eos_mark() const noexcept { return bool(m_value & 0x0002); } + bool use_descriptor() const noexcept { return bool(m_value & 0x0008); } + bool patch_data() const noexcept { return bool(m_value & 0x0020); } + bool strong_encryption() const noexcept { return bool(m_value & 0x0040); } + bool utf8_encoding() const noexcept { return bool(m_value & 0x0800); } + bool directory_encryption() const noexcept { return bool(m_value & 0x2000); } private: std::uint16_t m_value; @@ -653,6 +714,8 @@ private: GLOBAL VARIABLES ***************************************************************************/ +archive_category_impl const f_archive_category_instance; + std::array<zip_file_impl::ptr, zip_file_impl::CACHE_SIZE> zip_file_impl::s_cache; std::mutex zip_file_impl::s_cache_mutex; @@ -663,33 +726,38 @@ std::mutex zip_file_impl::s_cache_mutex; to the cache -------------------------------------------------*/ -void zip_file_impl::close(ptr &&zip) +void zip_file_impl::close(ptr &&zip) noexcept { - if (!zip) return; + // if the filename isn't empty, the cached directory can be reused + if (zip && !zip->m_filename.empty()) + { + // close the open files + osd_printf_verbose("unzip: closing archive file %s and sending to cache\n", zip->m_filename); + zip->m_file.reset(); - // close the open files - osd_printf_verbose("unzip: closing archive file %s and sending to cache\n", zip->m_filename); - zip->m_file.reset(); + // find the first nullptr entry in the cache + std::lock_guard<std::mutex> guard(s_cache_mutex); + std::size_t cachenum; + for (cachenum = 0; cachenum < s_cache.size(); cachenum++) + if (!s_cache[cachenum]) + break; - // find the first nullptr entry in the cache - std::lock_guard<std::mutex> guard(s_cache_mutex); - std::size_t cachenum; - for (cachenum = 0; cachenum < s_cache.size(); cachenum++) - if (!s_cache[cachenum]) - break; + // if no room left in the cache, free the bottommost entry + if (cachenum == s_cache.size()) + { + cachenum--; + osd_printf_verbose("unzip: removing %s from cache to make space\n", s_cache[cachenum]->m_filename); + s_cache[cachenum].reset(); + } - // if no room left in the cache, free the bottommost entry - if (cachenum == s_cache.size()) - { - cachenum--; - osd_printf_verbose("unzip: removing %s from cache to make space\n", s_cache[cachenum]->m_filename); - s_cache[cachenum].reset(); + // move everyone else down and place us at the top + for ( ; cachenum > 0; cachenum--) + s_cache[cachenum] = std::move(s_cache[cachenum - 1]); + s_cache[0] = std::move(zip); } - // move everyone else down and place us at the top - for ( ; cachenum > 0; cachenum--) - s_cache[cachenum] = std::move(s_cache[cachenum - 1]); - s_cache[0] = std::move(zip); + // make sure it's cleaned up + zip.reset(); } @@ -702,7 +770,7 @@ void zip_file_impl::close(ptr &&zip) entry in the ZIP -------------------------------------------------*/ -int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname, bool partialpath) +int zip_file_impl::search(std::uint32_t search_crc, std::string_view search_filename, bool matchcrc, bool matchname, bool partialpath) noexcept { // if we're at or past the end, we're done while ((m_cd_pos + central_dir_entry_reader::minimum_length()) <= m_ecd.cd_size) @@ -712,98 +780,123 @@ int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_fi if (!reader.signature_correct() || ((m_cd_pos + reader.total_length()) > m_ecd.cd_size)) break; - // extract file header info - m_header.version_created = reader.version_created(); - m_header.version_needed = reader.version_needed(); - m_header.bit_flag = reader.general_flag(); - m_header.compression = reader.compression_method(); - m_header.crc = reader.crc32(); - m_header.compressed_length = reader.compressed_size(); - m_header.uncompressed_length = reader.uncompressed_size(); - m_header.start_disk_number = reader.start_disk(); - m_header.local_header_offset = reader.header_offset(); - - // don't immediately decode DOS timestamp - it's expensive - m_header.modified_date = reader.modified_date(); - m_header.modified_time = reader.modified_time(); - m_header.modified_cached = false; - - // advance the position - m_cd_pos += reader.total_length(); - - // copy the filename - bool is_utf8(general_flag_reader(m_header.bit_flag).utf8_encoding()); - reader.file_name(m_header.file_name); - - // walk the extra data - for (auto extra = reader.extra_field(); extra.length_sufficient(); extra = extra.next()) + // setting std::string can raise allocation exceptions + try { - // look for ZIP64 extended info - if ((extra.header_id() == 0x0001) && (extra.data_size() >= zip64_ext_info_reader::minimum_length())) + // extract file header info + file_header header; + header.version_created = reader.version_created(); + header.version_needed = reader.version_needed(); + header.bit_flag = reader.general_flag(); + header.compression = reader.compression_method(); + header.crc = reader.crc32(); + header.compressed_length = reader.compressed_size(); + header.uncompressed_length = reader.uncompressed_size(); + header.start_disk_number = reader.start_disk(); + header.local_header_offset = reader.header_offset(); + + // don't immediately decode DOS timestamp - it's expensive + header.modified_date = reader.modified_date(); + header.modified_time = reader.modified_time(); + header.modified_cached = false; + + // copy the filename + bool is_utf8(general_flag_reader(header.bit_flag).utf8_encoding()); + reader.file_name(header.file_name); + + // walk the extra data + for (auto extra = reader.extra_field(); extra.length_sufficient(); extra = extra.next()) { - zip64_ext_info_reader const ext64(reader, extra); - if (extra.data_size() >= ext64.total_length()) + // look for ZIP64 extended info + if ((extra.header_id() == 0x0001) && (extra.data_size() >= zip64_ext_info_reader::minimum_length())) { - m_header.compressed_length = ext64.compressed_size(); - m_header.uncompressed_length = ext64.uncompressed_size(); - m_header.start_disk_number = ext64.start_disk(); - m_header.local_header_offset = ext64.header_offset(); + zip64_ext_info_reader const ext64(reader, extra); + if (extra.data_size() >= ext64.total_length()) + { + header.compressed_length = ext64.compressed_size(); + header.uncompressed_length = ext64.uncompressed_size(); + header.start_disk_number = ext64.start_disk(); + header.local_header_offset = ext64.header_offset(); + } } - } - // look for Info-ZIP UTF-8 path - if (!is_utf8 && (extra.header_id() == 0x7075) && (extra.data_size() >= utf8_path_reader::minimum_length())) - { - utf8_path_reader const utf8path(extra); - if (utf8path.version() == 1) + // look for Info-ZIP UTF-8 path + if (!is_utf8 && (extra.header_id() == 0x7075) && (extra.data_size() >= utf8_path_reader::minimum_length())) { - auto const addr(m_header.file_name.empty() ? nullptr : &m_header.file_name[0]); - auto const length(m_header.file_name.empty() ? 0 : m_header.file_name.length() * sizeof(m_header.file_name[0])); - auto const crc(crc32_creator::simple(addr, length)); - if (utf8path.name_crc32() == crc.m_raw) + utf8_path_reader const utf8path(extra); + if (utf8path.version() == 1) { - utf8path.unicode_name(m_header.file_name); - is_utf8 = true; + auto const addr(header.file_name.empty() ? nullptr : &header.file_name[0]); + auto const length(header.file_name.empty() ? 0 : header.file_name.length() * sizeof(header.file_name[0])); + auto const crc(crc32_creator::simple(addr, length)); + if (utf8path.name_crc32() == crc.m_raw) + { + utf8path.unicode_name(header.file_name); + is_utf8 = true; + } } } - } - // look for NTFS extra field - if ((extra.header_id() == 0x000a) && (extra.data_size() >= ntfs_reader::minimum_length())) - { - ntfs_reader const ntfs(extra); - for (auto tag = ntfs.tag1(); tag.length_sufficient(); tag = tag.next()) + // look for NTFS extra field + if ((extra.header_id() == 0x000a) && (extra.data_size() >= ntfs_reader::minimum_length())) { - if ((tag.tag() == 0x0001) && (tag.size() >= ntfs_times_reader::minimum_length())) + ntfs_reader const ntfs(extra); + for (auto tag = ntfs.tag1(); tag.length_sufficient(); tag = tag.next()) { - ntfs_times_reader const times(tag); - ntfs_duration const ticks(times.mtime()); - m_header.modified = system_clock_time_point_from_ntfs_duration(ticks); - m_header.modified_cached = true; + if ((tag.tag() == 0x0001) && (tag.size() >= ntfs_times_reader::minimum_length())) + { + ntfs_times_reader const times(tag); + ntfs_duration const ticks(times.mtime()); + try + { + header.modified = system_clock_time_point_from_ntfs_duration(ticks); + header.modified_cached = true; + } + catch (...) + { + // out-of-range exception - let it fall back to DOS-style timestamp + } + } } } } - } - // FIXME: if (!is_utf8) convert filename to UTF8 (assume CP437 or something) + // FIXME: if (!is_utf8) convert filename to UTF8 (assume CP437 or something) - // chop off trailing slash for directory entries - bool const is_dir(!m_header.file_name.empty() && (m_header.file_name.back() == '/')); - if (is_dir) m_header.file_name.resize(m_header.file_name.length() - 1); + // chop off trailing slash for directory entries + bool const is_dir(!header.file_name.empty() && (header.file_name.back() == '/')); + if (is_dir) + header.file_name.resize(header.file_name.length() - 1); - // check to see if it matches query - bool const crcmatch(search_crc == m_header.crc); - auto const partialoffset(m_header.file_name.length() - search_filename.length()); - bool const partialpossible((m_header.file_name.length() > search_filename.length()) && (m_header.file_name[partialoffset - 1] == '/')); - const bool namematch( - !core_stricmp(search_filename.c_str(), m_header.file_name.c_str()) || - (partialpath && partialpossible && !core_stricmp(search_filename.c_str(), m_header.file_name.c_str() + partialoffset))); + // advance the position + m_header = std::move(header); + m_curr_is_dir = is_dir; + m_cd_pos += reader.total_length(); + } + catch (...) + { + break; + } - bool const found = ((!matchcrc && !matchname) || !is_dir) && (!matchcrc || crcmatch) && (!matchname || namematch); - if (found) + // quick return if not required to match on name + if (!matchname) { - m_curr_is_dir = is_dir; - return 0; + if (!matchcrc || ((search_crc == m_header.crc) && !m_curr_is_dir)) + return 0; + } + else if (!m_curr_is_dir) + { + // check to see if it matches query + auto const partialoffset = m_header.file_name.length() - search_filename.length(); + const bool namematch = + (search_filename.length() == m_header.file_name.length()) && + (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_header.file_name[0], search_filename.length())); + bool const partialmatch = + partialpath && + ((m_header.file_name.length() > search_filename.length()) && (m_header.file_name[partialoffset - 1] == '/')) && + (search_filename.empty() || !core_strnicmp(&search_filename[0], &m_header.file_name[partialoffset], search_filename.length())); + if ((!matchcrc || (search_crc == m_header.crc)) && (namematch || partialmatch)) + return 0; } } return -1; @@ -815,11 +908,8 @@ int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_fi from a ZIP into the target buffer -------------------------------------------------*/ -archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length) +std::error_condition zip_file_impl::decompress(void *buffer, std::size_t length) noexcept { - archive_file::error ziperr; - std::uint64_t offset; - // if we don't have enough buffer, error if (length < m_header.uncompressed_length) { @@ -835,33 +925,29 @@ archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length } // get the compressed data offset - ziperr = get_compressed_data_offset(offset); - if (ziperr != archive_file::error::NONE) + std::uint64_t offset; + auto const ziperr = get_compressed_data_offset(offset); + if (ziperr) return ziperr; // handle compression types switch (m_header.compression) { case 0: - ziperr = decompress_data_type_0(offset, buffer, length); - break; + return decompress_data_type_0(offset, buffer, length); case 8: - ziperr = decompress_data_type_8(offset, buffer, length); - break; + return decompress_data_type_8(offset, buffer, length); case 14: - ziperr = decompress_data_type_14(offset, buffer, length); - break; + return decompress_data_type_14(offset, buffer, length); default: osd_printf_error( "unzip: %s in %s uses unsupported compression method %u\n", - m_header.file_name.c_str(), m_filename.c_str(), m_header.compression); - ziperr = archive_file::error::UNSUPPORTED; - break; + m_header.file_name, m_filename, m_header.compression); + return archive_file::error::UNSUPPORTED; } - return ziperr; } @@ -874,16 +960,16 @@ archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length read_ecd - read the ECD data -------------------------------------------------*/ -archive_file::error zip_file_impl::read_ecd() +std::error_condition zip_file_impl::read_ecd() noexcept { // make sure the file handle is open auto const ziperr = reopen(); - if (ziperr != archive_file::error::NONE) + if (ziperr) return ziperr; // we may need multiple tries - osd_file::error error; - std::uint32_t read_length; + std::error_condition filerr; + std::size_t read_length; std::uint32_t buflen = 1024; while (buflen < 65536) { @@ -893,19 +979,26 @@ archive_file::error zip_file_impl::read_ecd() // allocate buffer std::unique_ptr<std::uint8_t []> buffer; - try { buffer.reset(new std::uint8_t[buflen + 1]); } - catch (...) + buffer.reset(new (std::nothrow) std::uint8_t[buflen + 1]); + if (!buffer) { osd_printf_error("unzip: %s failed to allocate memory for ECD search\n", m_filename); - return archive_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } // read in one buffers' worth of data - error = m_file->read(&buffer[0], m_length - buflen, buflen, read_length); - if ((error != osd_file::error::NONE) || (read_length != buflen)) + filerr = m_file->read_at(m_length - buflen, &buffer[0], buflen, read_length); + if (filerr) + { + osd_printf_error( + "unzip: error reading %s to search for ECD (%s:%d %s)\n", + m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; + } + if (read_length != buflen) { - osd_printf_error("unzip: %s error reading file to search for ECD (%d)\n", m_filename, int(error)); - return archive_file::error::FILE_ERROR; + osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s to search for ECD\n", m_filename); + return archive_file::error::FILE_TRUNCATED; } // find the ECD signature @@ -935,19 +1028,26 @@ archive_file::error zip_file_impl::read_ecd() if ((m_length - buflen + offset) < ecd64_locator_reader::minimum_length()) { osd_printf_verbose("unzip: %s too small to contain ZIP64 ECD locator\n", m_filename); - return archive_file::error::NONE; + return std::error_condition(); } // try to read the ZIP64 ECD locator - error = m_file->read( - &buffer[0], + filerr = m_file->read_at( m_length - buflen + offset - ecd64_locator_reader::minimum_length(), + &buffer[0], ecd64_locator_reader::minimum_length(), read_length); - if ((error != osd_file::error::NONE) || (read_length != ecd64_locator_reader::minimum_length())) + if (filerr) + { + osd_printf_error( + "unzip: error reading %s to search for ZIP64 ECD locator (%s:%d %s)\n", + m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; + } + if (read_length != ecd64_locator_reader::minimum_length()) { - osd_printf_error("unzip: error reading %s to search for ZIP64 ECD locator (%d)\n", m_filename, int(error)); - return archive_file::error::FILE_ERROR; + osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s to search for ZIP64 ECD locator\n", m_filename); + return archive_file::error::FILE_TRUNCATED; } // if the signature isn't correct, it's not a ZIP64 archive @@ -955,7 +1055,7 @@ archive_file::error zip_file_impl::read_ecd() if (!ecd64_loc_rd.signature_correct()) { osd_printf_verbose("unzip: %s has no ZIP64 ECD locator\n", m_filename); - return archive_file::error::NONE; + return std::error_condition(); } // check that the ZIP64 ECD is in this segment (assuming this segment is the last segment) @@ -966,11 +1066,13 @@ archive_file::error zip_file_impl::read_ecd() } // try to read the ZIP64 ECD - error = m_file->read(&buffer[0], ecd64_loc_rd.ecd64_offset(), ecd64_reader::minimum_length(), read_length); - if (error != osd_file::error::NONE) + filerr = m_file->read_at(ecd64_loc_rd.ecd64_offset(), &buffer[0], ecd64_reader::minimum_length(), read_length); + if (filerr) { - osd_printf_error("unzip: error reading %s ZIP64 ECD (%d)\n", m_filename, int(error)); - return archive_file::error::FILE_ERROR; + osd_printf_error( + "unzip: error reading %s ZIP64 ECD (%s:%d %s)\n", + m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } if (read_length != ecd64_reader::minimum_length()) { @@ -983,8 +1085,8 @@ archive_file::error zip_file_impl::read_ecd() if (!ecd64_rd.signature_correct()) { osd_printf_error( - "unzip: %s ZIP64 ECD has incorrect signature 0x%08lx\n", - m_filename.c_str(), long(ecd64_rd.signature())); + "unzip: %s ZIP64 ECD has incorrect signature 0x%08x\n", + m_filename, ecd64_rd.signature()); return archive_file::error::BAD_SIGNATURE; } if (ecd64_rd.total_length() < ecd64_reader::minimum_length()) @@ -996,7 +1098,7 @@ archive_file::error zip_file_impl::read_ecd() { osd_printf_error( "unzip: %s ZIP64 ECD requires unsupported version %u.%u\n", - m_filename.c_str(), unsigned(ecd64_rd.version_needed() / 10), unsigned(ecd64_rd.version_needed() % 10)); + m_filename, ecd64_rd.version_needed() / 10, ecd64_rd.version_needed() % 10); return archive_file::error::UNSUPPORTED; } osd_printf_verbose("unzip: found %s ZIP64 ECD\n", m_filename); @@ -1009,7 +1111,7 @@ archive_file::error zip_file_impl::read_ecd() m_ecd.cd_size = ecd64_rd.dir_size(); m_ecd.cd_start_disk_offset = ecd64_rd.dir_offset(); - return archive_file::error::NONE; + return std::error_condition(); } // didn't find it; free this buffer and expand our search @@ -1024,7 +1126,7 @@ archive_file::error zip_file_impl::read_ecd() } } osd_printf_error("unzip: %s couldn't find ECD in last 64KiB\n", m_filename); - return archive_file::error::OUT_OF_MEMORY; + return archive_file::error::UNSUPPORTED; // TODO: revisit this error code } @@ -1033,7 +1135,7 @@ archive_file::error zip_file_impl::read_ecd() offset of the compressed data -------------------------------------------------*/ -archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) +std::error_condition zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) noexcept { // don't support a number of features general_flag_reader const flags(m_header.bit_flag); @@ -1046,7 +1148,7 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off { osd_printf_error( "unzip: %s in %s requires unsupported version %u.%u\n", - m_header.file_name.c_str(), m_filename.c_str(), unsigned(m_header.version_needed / 10), unsigned(m_header.version_needed % 10)); + m_header.file_name, m_filename, m_header.version_needed / 10, m_header.version_needed % 10); return archive_file::error::UNSUPPORTED; } if (flags.encrypted() || flags.strong_encryption()) @@ -1062,24 +1164,24 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off // make sure the file handle is open auto const ziperr = reopen(); - if (ziperr != archive_file::error::NONE) + if (ziperr) return ziperr; // now go read the fixed-sized part of the local file header - std::uint32_t read_length; - auto const error = m_file->read(&m_buffer[0], m_header.local_header_offset, local_file_header_reader::minimum_length(), read_length); - if (error != osd_file::error::NONE) + std::size_t read_length; + std::error_condition const filerr = m_file->read_at(m_header.local_header_offset, &m_buffer[0], local_file_header_reader::minimum_length(), read_length); + if (filerr) { osd_printf_error( - "unzip: error reading local file header for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(error)); - return archive_file::error::FILE_ERROR; + "unzip: error reading local file header for %s in %s (%s:%d %s)\n", + m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } if (read_length != local_file_header_reader::minimum_length()) { osd_printf_error( "unzip: unexpectedly reached end-of-file while reading local file header for %s in %s\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::FILE_TRUNCATED; } @@ -1088,13 +1190,13 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off if (!reader.signature_correct()) { osd_printf_error( - "unzip: local file header for %s in %s has incorrect signature %04lx\n", - m_header.file_name.c_str(), m_filename.c_str(), long(reader.signature())); + "unzip: local file header for %s in %s has incorrect signature %04x\n", + m_header.file_name, m_filename, reader.signature()); return archive_file::error::BAD_SIGNATURE; } offset = m_header.local_header_offset + reader.total_length(); - return archive_file::error::NONE; + return std::error_condition(); } @@ -1108,24 +1210,28 @@ archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &off type 0 data (which is uncompressed) -------------------------------------------------*/ -archive_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length) +std::error_condition zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::size_t length) noexcept { // the data is uncompressed; just read it - std::uint32_t read_length(0); - auto const filerr = m_file->read(buffer, offset, m_header.compressed_length, read_length); - if (filerr != osd_file::error::NONE) + std::size_t read_length(0); + std::error_condition const filerr = m_file->read_at(offset, buffer, m_header.compressed_length, read_length); + if (filerr) { - osd_printf_error("unzip: error reading %s from %s (%d)\n", m_header.file_name, m_filename, int(filerr)); - return archive_file::error::FILE_ERROR; + osd_printf_error( + "unzip: error reading %s from %s (%s:%d %s)\n", + m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } else if (read_length != m_header.compressed_length) { - osd_printf_error("unzip: unexpectedly reached end-of-file while reading %s from %s\n", m_header.file_name, m_filename); + osd_printf_error( + "unzip: unexpectedly reached end-of-file while reading %s from %s\n", + m_header.file_name, m_filename); return archive_file::error::FILE_TRUNCATED; } else { - return archive_file::error::NONE; + return std::error_condition(); } } @@ -1135,8 +1241,23 @@ archive_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, type 8 data (which is deflated) -------------------------------------------------*/ -archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length) +std::error_condition zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::size_t length) noexcept { + auto const convert_zerr = + [] (int e) -> std::error_condition + { + switch (e) + { + case Z_OK: + return std::error_condition(); + case Z_ERRNO: + return std::error_condition(errno, std::generic_category()); + case Z_MEM_ERROR: + return std::errc::not_enough_memory; + default: + return archive_file::error::DECOMPRESS_ERROR; + } + }; std::uint64_t input_remaining = m_header.compressed_length; int zerr; @@ -1153,38 +1274,39 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, zerr = inflateInit2(&stream, -MAX_WBITS); if (zerr != Z_OK) { + auto result = convert_zerr(zerr); osd_printf_error( "unzip: error allocating zlib stream to inflate %s from %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), zerr); - return archive_file::error::DECOMPRESS_ERROR; + m_header.file_name, m_filename, zerr); + return result; } // loop until we're done while (true) { // read in the next chunk of data - std::uint32_t read_length(0); - auto const filerr = m_file->read( - &m_buffer[0], + std::size_t read_length(0); + auto const filerr = m_file->read_at( offset, - std::uint32_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())), + &m_buffer[0], + std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())), read_length); - if (filerr != osd_file::error::NONE) + if (filerr) { osd_printf_error( - "unzip: error reading compressed data for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(filerr)); + "unzip: error reading compressed data for %s in %s (%s:%d %s)\n", + m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message()); inflateEnd(&stream); - return archive_file::error::FILE_ERROR; + return filerr; } offset += read_length; // if we read nothing, but still have data left, the file is truncated - if ((read_length == 0) && (input_remaining > 0)) + if (!read_length && input_remaining) { osd_printf_error( "unzip: unexpectedly reached end-of-file while reading compressed data for %s in %s\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); inflateEnd(&stream); return archive_file::error::FILE_TRUNCATED; } @@ -1206,9 +1328,12 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, } else if (zerr != Z_OK) { - osd_printf_error("unzip: error inflating %s from %s (%d)\n", m_header.file_name, m_filename, zerr); + auto result = convert_zerr(zerr); + osd_printf_error( + "unzip: error inflating %s from %s (%d)\n", + m_header.file_name, m_filename, zerr); inflateEnd(&stream); - return archive_file::error::DECOMPRESS_ERROR; + return result; } } @@ -1216,20 +1341,23 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, zerr = inflateEnd(&stream); if (zerr != Z_OK) { - osd_printf_error("unzip: error finishing inflation of %s from %s (%d)\n", m_header.file_name, m_filename, zerr); - return archive_file::error::DECOMPRESS_ERROR; + auto result = convert_zerr(zerr); + osd_printf_error( + "unzip: error finishing inflation of %s from %s (%d)\n", + m_header.file_name, m_filename, zerr); + return result; } // if anything looks funny, report an error - if ((stream.avail_out > 0) || (input_remaining > 0)) + if (stream.avail_out || input_remaining) { osd_printf_error( "unzip: inflation of %s from %s doesn't appear to have completed correctly\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::DECOMPRESS_ERROR; } - return archive_file::error::NONE; + return std::error_condition(); } @@ -1238,7 +1366,7 @@ archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, type 14 data (LZMA) -------------------------------------------------*/ -archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, void *buffer, std::uint32_t length) +std::error_condition zip_file_impl::decompress_data_type_14(std::uint64_t offset, void *buffer, std::size_t length) noexcept { // two-byte version // two-byte properties size (little-endian) @@ -1253,15 +1381,15 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, SizeT output_remaining(length); std::uint64_t input_remaining(m_header.compressed_length); - std::uint32_t read_length; - osd_file::error filerr; + std::size_t read_length; + std::error_condition filerr; SRes lzerr; ELzmaStatus lzstatus(LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK); // reset the stream ISzAlloc alloc_imp; - alloc_imp.Alloc = [](void *p, std::size_t size) -> void * { return (size == 0) ? nullptr : std::malloc(size); }; - alloc_imp.Free = [](void *p, void *address) -> void { std::free(address); }; + alloc_imp.Alloc = [] (void *p, std::size_t size) -> void * { return size ? std::malloc(size) : nullptr; }; + alloc_imp.Free = [] (void *p, void *address) -> void { std::free(address); }; CLzmaDec stream; LzmaDec_Construct(&stream); @@ -1270,16 +1398,16 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, { osd_printf_error( "unzip:compressed data for %s in %s is too small to hold LZMA properties header\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::DECOMPRESS_ERROR; } - filerr = m_file->read(&m_buffer[0], offset, 4, read_length); - if (filerr != osd_file::error::NONE) + filerr = m_file->read_at(offset, &m_buffer[0], 4, read_length); + if (filerr) { osd_printf_error( - "unzip: error reading LZMA properties header for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(filerr)); - return archive_file::error::FILE_ERROR; + "unzip: error reading LZMA properties header for %s in %s (%s:%d %s)\n", + m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } offset += read_length; input_remaining -= read_length; @@ -1287,7 +1415,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, { osd_printf_error( "unzip: unexpectedly reached end-of-file while reading LZMA properties header for %s in %s\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::FILE_TRUNCATED; } std::uint16_t const props_size((std::uint16_t(m_buffer[3]) << 8) | std::uint16_t(m_buffer[2])); @@ -1295,23 +1423,23 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, { osd_printf_error( "unzip: %s in %s has excessively large LZMA properties\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::UNSUPPORTED; } else if (props_size > input_remaining) { osd_printf_error( "unzip:compressed data for %s in %s is too small to hold LZMA properties\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::DECOMPRESS_ERROR; } - filerr = m_file->read(&m_buffer[0], offset, props_size, read_length); - if (filerr != osd_file::error::NONE) + filerr = m_file->read_at(offset, &m_buffer[0], props_size, read_length); + if (filerr) { osd_printf_error( - "unzip: error reading LZMA properties for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(filerr)); - return archive_file::error::FILE_ERROR; + "unzip: error reading LZMA properties for %s in %s (%s:%d %s)\n", + m_header.file_name, m_filename, filerr.category().name(), filerr.value(), filerr.message()); + return filerr; } offset += read_length; input_remaining -= read_length; @@ -1319,7 +1447,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, { osd_printf_error( "unzip: unexpectedly reached end-of-file while reading LZMA properties for %s in %s\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); return archive_file::error::FILE_TRUNCATED; } @@ -1329,14 +1457,21 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, { osd_printf_error( "unzip: memory error allocating LZMA decoder to decompress %s from %s\n", - m_header.file_name.c_str(), m_filename.c_str()); - return archive_file::error::OUT_OF_MEMORY; + m_header.file_name, m_filename); + return std::errc::not_enough_memory; + } + else if (SZ_ERROR_UNSUPPORTED) + { + osd_printf_error( + "unzip: LZMA decoder does not support properties for %s in %s\n", + m_header.file_name, m_filename); + return archive_file::error::UNSUPPORTED; } else if (SZ_OK != lzerr) { osd_printf_error( "unzip: error allocating LZMA decoder to decompress %s from %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(lzerr)); + m_header.file_name, m_filename, int(lzerr)); return archive_file::error::DECOMPRESS_ERROR; } LzmaDec_Init(&stream); @@ -1345,28 +1480,28 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, while (0 < input_remaining) { // read in the next chunk of data - filerr = m_file->read( - &m_buffer[0], + filerr = m_file->read_at( offset, - std::uint32_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())), + &m_buffer[0], + std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())), read_length); - if (filerr != osd_file::error::NONE) + if (filerr) { osd_printf_error( - "unzip: error reading compressed data for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(filerr)); + "unzip: error reading compressed data for %s in %s (%s)\n", + m_header.file_name, m_filename); LzmaDec_Free(&stream, &alloc_imp); - return archive_file::error::FILE_ERROR; + return filerr; } offset += read_length; input_remaining -= read_length; // if we read nothing, but still have data left, the file is truncated - if ((0 == read_length) && (0 < input_remaining)) + if (!read_length && input_remaining) { osd_printf_error( "unzip: unexpectedly reached end-of-file while reading compressed data for %s in %s\n", - m_header.file_name.c_str(), m_filename.c_str()); + m_header.file_name, m_filename); LzmaDec_Free(&stream, &alloc_imp); return archive_file::error::FILE_TRUNCATED; } @@ -1381,7 +1516,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, &output_remaining, reinterpret_cast<Byte const *>(&m_buffer[0]), &len, - ((0 == input_remaining) && eos_mark) ? LZMA_FINISH_END : LZMA_FINISH_ANY, + (!input_remaining && eos_mark) ? LZMA_FINISH_END : LZMA_FINISH_ANY, &lzstatus); if (SZ_OK != lzerr) { @@ -1397,25 +1532,25 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, // if anything looks funny, report an error if (LZMA_STATUS_FINISHED_WITH_MARK == lzstatus) { - return archive_file::error::NONE; + return std::error_condition(); } else if (eos_mark) { osd_printf_error( "unzip: LZMA end mark not found for %s in %s (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(lzstatus)); + m_header.file_name, m_filename, int(lzstatus)); return archive_file::error::DECOMPRESS_ERROR; } else if (LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK != lzstatus) { osd_printf_error( "unzip: LZMA decompression of %s from %s doesn't appear to have completed correctly (%d)\n", - m_header.file_name.c_str(), m_filename.c_str(), int(lzstatus)); + m_header.file_name, m_filename, int(lzstatus)); return archive_file::error::DECOMPRESS_ERROR; } else { - return archive_file::error::NONE; + return std::error_condition(); } } @@ -1427,7 +1562,7 @@ archive_file::error zip_file_impl::decompress_data_type_14(std::uint64_t offset, un7z.cpp TRAMPOLINES ***************************************************************************/ -void m7z_file_cache_clear(); +void m7z_file_cache_clear() noexcept; @@ -1439,7 +1574,7 @@ void m7z_file_cache_clear(); zip_file_open - opens a ZIP file for reading -------------------------------------------------*/ -archive_file::error archive_file::open_zip(const std::string &filename, ptr &result) +std::error_condition archive_file::open_zip(std::string_view filename, ptr &result) noexcept { // ensure we start with a nullptr result result.reset(); @@ -1450,21 +1585,49 @@ archive_file::error archive_file::open_zip(const std::string &filename, ptr &res if (!newimpl) { // allocate memory for the zip_file structure - try { newimpl = std::make_unique<zip_file_impl>(filename); } - catch (...) { return error::OUT_OF_MEMORY; } - auto const ziperr = newimpl->initialize(); - if (ziperr != error::NONE) return ziperr; + try { newimpl = std::make_unique<zip_file_impl>(std::string(filename)); } + catch (...) { return std::errc::not_enough_memory; } + auto const err = newimpl->initialize(); + if (err) + return err; + } + + // allocate the archive API wrapper + result.reset(new (std::nothrow) zip_file_wrapper(std::move(newimpl))); + if (result) + { + return std::error_condition(); + } + else + { + zip_file_impl::close(std::move(newimpl)); + return std::errc::not_enough_memory; } +} - try +std::error_condition archive_file::open_zip(random_read::ptr &&file, ptr &result) noexcept +{ + // ensure we start with a nullptr result + result.reset(); + + // allocate memory for the zip_file structure + zip_file_impl::ptr newimpl(new (std::nothrow) zip_file_impl(std::move(file))); + if (!newimpl) + return std::errc::not_enough_memory; + auto const err = newimpl->initialize(); + if (err) + return err; + + // allocate the archive API wrapper + result.reset(new (std::nothrow) zip_file_wrapper(std::move(newimpl))); + if (result) { - result = std::make_unique<zip_file_wrapper>(std::move(newimpl)); - return error::NONE; + return std::error_condition(); } - catch (...) + else { zip_file_impl::close(std::move(newimpl)); - return error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -1474,7 +1637,7 @@ archive_file::error archive_file::open_zip(const std::string &filename, ptr &res cache and free all memory -------------------------------------------------*/ -void archive_file::cache_clear() +void archive_file::cache_clear() noexcept { zip_file_impl::cache_clear(); m7z_file_cache_clear(); @@ -1485,4 +1648,15 @@ archive_file::~archive_file() { } + +/*------------------------------------------------- + archive_category - gets the archive error + category instance +-------------------------------------------------*/ + +std::error_category const &archive_category() noexcept +{ + return f_archive_category_instance; +} + } // namespace util diff --git a/src/lib/util/unzip.h b/src/lib/util/unzip.h index b1ddb7a27d1..2108eadee28 100644 --- a/src/lib/util/unzip.h +++ b/src/lib/util/unzip.h @@ -7,19 +7,24 @@ archive file management. ***************************************************************************/ +#ifndef MAME_LIB_UTIL_UNZIP_H +#define MAME_LIB_UTIL_UNZIP_H #pragma once -#ifndef MAME_LIB_UTIL_UNZIP_H -#define MAME_LIB_UTIL_UNZIP_H +#include "utilfwd.h" #include <chrono> #include <cstdint> #include <memory> #include <string> +#include <string_view> +#include <system_error> +#include <type_traits> namespace util { + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -30,12 +35,9 @@ class archive_file public: // Error types - enum class error + enum class error : int { - NONE = 0, - OUT_OF_MEMORY, - FILE_ERROR, - BAD_SIGNATURE, + BAD_SIGNATURE = 1, DECOMPRESS_ERROR, FILE_TRUNCATED, FILE_CORRUPT, @@ -49,40 +51,54 @@ public: /* ----- archive file access ----- */ // open a ZIP file and parse its central directory - static error open_zip(const std::string &filename, ptr &zip); + static std::error_condition open_zip(std::string_view filename, ptr &result) noexcept; + static std::error_condition open_zip(std::unique_ptr<random_read> &&file, ptr &result) noexcept; // open a 7Z file and parse its central directory - static error open_7z(const std::string &filename, ptr &result); + static std::error_condition open_7z(std::string_view filename, ptr &result) noexcept; + static std::error_condition open_7z(std::unique_ptr<random_read> &&file, ptr &result) noexcept; // close an archive file (may actually be left open due to caching) virtual ~archive_file(); // clear out all open files from the cache - static void cache_clear(); + static void cache_clear() noexcept; /* ----- contained file access ----- */ // iterating over files - returns negative on reaching end - virtual int first_file() = 0; - virtual int next_file() = 0; + virtual int first_file() noexcept = 0; + virtual int next_file() noexcept = 0; // find a file index by crc, filename or both - returns non-negative on match - virtual int search(std::uint32_t crc) = 0; - virtual int search(const std::string &filename, bool partialpath) = 0; - virtual int search(std::uint32_t crc, const std::string &filename, bool partialpath) = 0; + virtual int search(std::uint32_t crc) noexcept = 0; + virtual int search(std::string_view filename, bool partialpath) noexcept = 0; + virtual int search(std::uint32_t crc, std::string_view filename, bool partialpath) noexcept = 0; // information on most recently found file - virtual bool current_is_directory() const = 0; - virtual const std::string ¤t_name() const = 0; - virtual std::uint64_t current_uncompressed_length() const = 0; - virtual std::chrono::system_clock::time_point current_last_modified() const = 0; - virtual std::uint32_t current_crc() const = 0; + virtual bool current_is_directory() const noexcept = 0; + virtual const std::string ¤t_name() const noexcept = 0; + virtual std::uint64_t current_uncompressed_length() const noexcept = 0; + virtual std::chrono::system_clock::time_point current_last_modified() const noexcept = 0; + virtual std::uint32_t current_crc() const noexcept = 0; // decompress the most recently found file in the ZIP - virtual error decompress(void *buffer, std::uint32_t length) = 0; + virtual std::error_condition decompress(void *buffer, std::size_t length) noexcept = 0; }; + +// error category for archive errors +std::error_category const &archive_category() noexcept; +inline std::error_condition make_error_condition(archive_file::error err) noexcept { return std::error_condition(int(err), archive_category()); } + } // namespace util + +namespace std { + +template <> struct is_error_condition_enum<util::archive_file::error> : public std::true_type { }; + +} // namespace std + #endif // MAME_LIB_UTIL_UNZIP_H diff --git a/src/lib/util/utilfwd.h b/src/lib/util/utilfwd.h new file mode 100644 index 00000000000..fefe0631c68 --- /dev/null +++ b/src/lib/util/utilfwd.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/********************************************************************** + + utilfwd.h + + Forward declarations of types + +**********************************************************************/ +#ifndef MAME_LIB_UTIL_UTILFWD_H +#define MAME_LIB_UTIL_UTILFWD_H + +// chd.h +class chd_file; + + +namespace util { + +// corefile.h +class core_file; + +// ioprocs.h +class read_stream; +class write_stream; +class read_write_stream; +class random_access; +class random_read; +class random_write; +class random_read_write; + +// unzip.h +class archive_file; + +} // namespace util + + +namespace util::xml { + +// xmlfile.h +class data_node; +class file; + +} // namespace util::xml + +#endif // MAME_LIB_UTIL_UTILFWD_H diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp index 023484010b8..f317319c8c3 100644 --- a/src/lib/util/zippath.cpp +++ b/src/lib/util/zippath.cpp @@ -9,13 +9,13 @@ ***************************************************************************/ #include "zippath.h" -#include "unzip.h" -#include "corestr.h" -#include <cstdlib> +#include "corestr.h" +#include "unzip.h" #include <cassert> #include <cctype> +#include <cstdlib> #include <forward_list> #include <new> @@ -192,7 +192,7 @@ int zippath_find_sub_path(archive_file &zipfile, std::string_view subpath, osd:: // true path and ZIP entry components // ------------------------------------------------- -osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::entry_type &entry_type, archive_file::ptr &zipfile, std::string &newpath) +std::error_condition zippath_resolve(std::string_view path, osd::directory::entry::entry_type &entry_type, archive_file::ptr &zipfile, std::string &newpath) { newpath.clear(); @@ -238,13 +238,13 @@ osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::en if (current_entry_type == osd::directory::entry::entry_type::NONE) { entry_type = osd::directory::entry::entry_type::NONE; - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; } // is this file a ZIP file? if ((current_entry_type == osd::directory::entry::entry_type::FILE) && - ((is_zip_file(apath_trimmed) && (archive_file::open_zip(apath_trimmed, zipfile) == archive_file::error::NONE)) || - (is_7z_file(apath_trimmed) && (archive_file::open_7z(apath_trimmed, zipfile) == archive_file::error::NONE)))) + ((is_zip_file(apath_trimmed) && !archive_file::open_zip(apath_trimmed, zipfile)) || + (is_7z_file(apath_trimmed) && !archive_file::open_7z(apath_trimmed, zipfile)))) { auto i = path.length() - apath.length(); while ((i > 0) && is_zip_path_separator(path[apath.length() + i - 1])) @@ -254,53 +254,20 @@ osd_file::error zippath_resolve(std::string_view path, osd::directory::entry::en // this was a true ZIP path - attempt to identify the type of path zippath_find_sub_path(*zipfile, newpath, current_entry_type); if (current_entry_type == osd::directory::entry::entry_type::NONE) - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; } else { // this was a normal path if (went_up) - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; newpath = path; } // success! entry_type = current_entry_type; - return osd_file::error::NONE; -} - - -// ------------------------------------------------- -// file_error_from_zip_error - translates a -// osd_file::error to a zip_error -// ------------------------------------------------- - -osd_file::error file_error_from_zip_error(archive_file::error ziperr) -{ - osd_file::error filerr; - switch(ziperr) - { - case archive_file::error::NONE: - filerr = osd_file::error::NONE; - break; - case archive_file::error::OUT_OF_MEMORY: - filerr = osd_file::error::OUT_OF_MEMORY; - break; - case archive_file::error::BAD_SIGNATURE: - case archive_file::error::DECOMPRESS_ERROR: - case archive_file::error::FILE_TRUNCATED: - case archive_file::error::FILE_CORRUPT: - case archive_file::error::UNSUPPORTED: - case archive_file::error::FILE_ERROR: - filerr = osd_file::error::INVALID_DATA; - break; - case archive_file::error::BUFFER_TOO_SMALL: - default: - filerr = osd_file::error::FAILURE; - break; - } - return filerr; + return std::error_condition(); } @@ -309,27 +276,24 @@ osd_file::error file_error_from_zip_error(archive_file::error ziperr) // from a zip file entry // ------------------------------------------------- -osd_file::error create_core_file_from_zip(archive_file &zip, util::core_file::ptr &file) +std::error_condition create_core_file_from_zip(archive_file &zip, util::core_file::ptr &file) { - osd_file::error filerr; - archive_file::error ziperr; + // TODO: would be more efficient if we could open a memory-based core_file with uninitialised contents and decompress into it + std::error_condition filerr; void *ptr = malloc(zip.current_uncompressed_length()); if (!ptr) { - filerr = osd_file::error::OUT_OF_MEMORY; + filerr = std::errc::not_enough_memory; goto done; } - ziperr = zip.decompress(ptr, zip.current_uncompressed_length()); - if (ziperr != archive_file::error::NONE) - { - filerr = file_error_from_zip_error(ziperr); + filerr = zip.decompress(ptr, zip.current_uncompressed_length()); + if (filerr) goto done; - } filerr = util::core_file::open_ram_copy(ptr, zip.current_uncompressed_length(), OPEN_FLAG_READ, file); - if (filerr != osd_file::error::NONE) + if (filerr) goto done; done: @@ -545,7 +509,7 @@ private: // zippath_directory::open - opens a directory // ------------------------------------------------- -osd_file::error zippath_directory::open(std::string_view path, ptr &directory) +std::error_condition zippath_directory::open(std::string_view path, ptr &directory) { try { @@ -553,34 +517,34 @@ osd_file::error zippath_directory::open(std::string_view path, ptr &directory) osd::directory::entry::entry_type entry_type; archive_file::ptr zipfile; std::string zipprefix; - osd_file::error const err = zippath_resolve(path, entry_type, zipfile, zipprefix); - if (osd_file::error::NONE != err) + std::error_condition const err = zippath_resolve(path, entry_type, zipfile, zipprefix); + if (err) return err; // we have to be a directory if (osd::directory::entry::entry_type::DIR != entry_type) - return osd_file::error::NOT_FOUND; + return std::errc::not_a_directory; // was the result a ZIP? if (zipfile) { directory = std::make_unique<archive_directory_impl>(std::move(zipfile), std::move(zipprefix)); - return osd_file::error::NONE; + return std::error_condition(); } else { // a conventional directory std::unique_ptr<filesystem_directory_impl> result(new filesystem_directory_impl(path)); if (!*result) - return osd_file::error::FAILURE; + return std::errc::io_error; // TODO: any way to give a better error here? directory = std::move(result); - return osd_file::error::NONE; + return std::error_condition(); } } catch (std::bad_alloc const &) { - return osd_file::error::OUT_OF_MEMORY; + return std::errc::not_enough_memory; } } @@ -681,7 +645,7 @@ std::string zippath_combine(const std::string &path1, const std::string &path2) // ------------------------------------------------- /** - * @fn osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path) + * @fn std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path) * * @brief Zippath fopen. * @@ -693,38 +657,35 @@ std::string zippath_combine(const std::string &path1, const std::string &path2) * @return A osd_file::error. */ -osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path) +std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path) { - osd_file::error filerr = osd_file::error::NOT_FOUND; - archive_file::error ziperr; + std::error_condition filerr = std::errc::no_such_file_or_directory; archive_file::ptr zip; - int header; - osd::directory::entry::entry_type entry_type; - int len; - /* first, set up the two types of paths */ + // first, set up the two types of paths std::string mainpath(filename); std::string subpath; file = nullptr; - /* loop through */ - while((file == nullptr) && (mainpath.length() > 0) - && ((openflags == OPEN_FLAG_READ) || subpath.empty())) + // loop through + while (!file && !mainpath.empty() && ((openflags == OPEN_FLAG_READ) || subpath.empty())) { - /* is the mainpath a ZIP path? */ + // is the mainpath a ZIP path? if (is_zip_file(mainpath) || is_7z_file(mainpath)) { - /* this file might be a zip file - lets take a look */ - ziperr = is_zip_file(mainpath) ? archive_file::open_zip(mainpath, zip) : archive_file::open_7z(mainpath, zip); - if (ziperr == archive_file::error::NONE) + // this file might be a zip file - lets take a look + std::error_condition const ziperr = is_zip_file(mainpath) ? archive_file::open_zip(mainpath, zip) : archive_file::open_7z(mainpath, zip); + if (!ziperr) { - /* it is a zip file - error if we're not opening for reading */ + // it is a zip file - error if we're not opening for reading if (openflags != OPEN_FLAG_READ) { - filerr = osd_file::error::ACCESS_DENIED; + filerr = std::errc::permission_denied; goto done; } + osd::directory::entry::entry_type entry_type; + int header; if (!subpath.empty()) header = zippath_find_sub_path(*zip, subpath, entry_type); else @@ -732,20 +693,20 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti if (header < 0) { - filerr = osd_file::error::NOT_FOUND; + filerr = std::errc::no_such_file_or_directory; goto done; } - /* attempt to read the file */ + // attempt to read the file filerr = create_core_file_from_zip(*zip, file); - if (filerr != osd_file::error::NONE) + if (filerr) goto done; - /* update subpath, if appropriate */ + // update subpath, if appropriate if (subpath.empty()) subpath.assign(zip->current_name()); - /* we're done */ + // we're done goto done; } } @@ -753,15 +714,15 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti if (subpath.empty()) filerr = util::core_file::open(std::string(filename), openflags, file); else - filerr = osd_file::error::NOT_FOUND; + filerr = std::errc::no_such_file_or_directory; - /* if we errored, then go up a directory */ - if (filerr != osd_file::error::NONE) + // if we errored, then go up a directory + if (filerr) { - /* go up a directory */ + // go up a directory auto temp = zippath_parent(mainpath); - /* append to the sub path */ + // append to the sub path if (!subpath.empty()) { std::string temp2; @@ -774,8 +735,8 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti mainpath = mainpath.substr(temp.length()); subpath.assign(mainpath); } - /* get the new main path, truncating path separators */ - len = temp.length(); + // get the new main path, truncating path separators + auto len = temp.length(); while (len > 0 && is_zip_file_separator(temp[len - 1])) len--; temp = temp.substr(0, len); @@ -784,14 +745,14 @@ osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, uti } done: - /* store the revised path */ + // store the revised path revised_path.clear(); - if (filerr == osd_file::error::NONE) + if (!filerr) { - /* canonicalize mainpath */ + // canonicalize mainpath std::string alloc_fullpath; filerr = osd_get_full_path(alloc_fullpath, mainpath); - if (filerr == osd_file::error::NONE) + if (!filerr) { revised_path = alloc_fullpath; if (!subpath.empty()) diff --git a/src/lib/util/zippath.h b/src/lib/util/zippath.h index 1eb92aa1c1d..955c75cfc8f 100644 --- a/src/lib/util/zippath.h +++ b/src/lib/util/zippath.h @@ -18,6 +18,7 @@ #include <string> #include <string_view> +#include <system_error> namespace util { @@ -32,7 +33,7 @@ public: typedef std::unique_ptr<zippath_directory> ptr; // opens a directory - static osd_file::error open(std::string_view path, ptr &directory); + static std::error_condition open(std::string_view path, ptr &directory); // closes a directory virtual ~zippath_directory(); @@ -63,7 +64,7 @@ std::string zippath_combine(const std::string &path1, const std::string &path2); // ----- file operations ----- // opens a zip path file -osd_file::error zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path); +std::error_condition zippath_fopen(std::string_view filename, uint32_t openflags, util::core_file::ptr &file, std::string &revised_path); } // namespace util |