diff options
Diffstat (limited to 'src/lib')
203 files changed, 13086 insertions, 8337 deletions
diff --git a/src/lib/formats/86f_dsk.cpp b/src/lib/formats/86f_dsk.cpp new file mode 100644 index 00000000000..654e847d8db --- /dev/null +++ b/src/lib/formats/86f_dsk.cpp @@ -0,0 +1,272 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, Carl + +#include "86f_dsk.h" + +#include "ioprocs.h" + +#include <cstring> +#include <tuple> + + +namespace { + +#define _86F_FORMAT_HEADER "86BF" + +#pragma pack(1) + +struct _86FIMG +{ + uint8_t headername[4]; + uint8_t minor_version; + uint8_t major_version; + uint16_t flags; + uint32_t firsttrackoffs; +}; + +#pragma pack() + +enum +{ + SURFACE_DESC = 1, + TYPE_MASK = 6, + TYPE_DD = 0, + TYPE_HD = 2, + TYPE_ED = 4, + TYPE_ED2000 = 6, + TWO_SIDES = 8, + WRITE_PROTECT = 0x10, + RPM_MASK = 0x60, + RPM_0 = 0, + RPM_1 = 0x20, + RPM_15 = 0x40, + RPM_2 = 0x60, + EXTRA_BC = 0x80, + ZONED_RPM = 0x100, + ZONE_PREA2_1 = 0, + ZONE_PREA2_2 = 0x200, + ZONE_A2 = 0x400, + ZONE_C64 = 0x600, + ENDIAN_BIG = 0x800, + RPM_FAST = 0x1000, + TOTAL_BC = 0x1000 +}; + +} // anonymous namespace + + +_86f_format::_86f_format() : floppy_image_format_t() +{ +} + +const char *_86f_format::name() const noexcept +{ + return "86f"; +} + +const char *_86f_format::description() const noexcept +{ + return "86f floppy image"; +} + +const char *_86f_format::extensions() const noexcept +{ + return "86f"; +} + +bool _86f_format::supports_save() const noexcept +{ + return false; +} + +int _86f_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint8_t header[4]; + auto const [err, actual] = read_at(io, 0, &header, sizeof(header)); + if (err) { + return 0; + } + if (!memcmp(header, _86F_FORMAT_HEADER, 4)) { + return FIFID_SIGN; + } + return 0; +} + +void _86f_format::generate_track_from_bitstream_with_weak(int track, int head, const uint8_t *trackbuf, const uint8_t *weak, int index_cell, int track_size, floppy_image &image) const +{ + int j = 0; + std::vector<uint32_t> &dest = image.get_buffer(track, head); + dest.clear(); + + for(int i=index_cell; i != track_size; i++, j++) { + int databit = trackbuf[i >> 3] & (0x80 >> (i & 7)); + int weakbit = weak ? weak[i >> 3] & (0x80 >> (i & 7)) : 0; + if(weakbit && databit) + dest.push_back(floppy_image::MG_D | (j*2+1)); + else if(weakbit && !databit) + dest.push_back(floppy_image::MG_N | (j*2+1)); + else if(databit) + dest.push_back(floppy_image::MG_F | (j*2+1)); + } + for(int i=0; i != index_cell; i++, j++) { + int databit = trackbuf[i >> 3] & (0x80 >> (i & 7)); + int weakbit = weak ? weak[i >> 3] & (0x80 >> (i & 7)) : 0; + if(weakbit && databit) + dest.push_back(floppy_image::MG_D | (j*2+1)); + else if(weakbit && !databit) + dest.push_back(floppy_image::MG_N | (j*2+1)); + else if(databit) + dest.push_back(floppy_image::MG_F | (j*2+1)); + } + + normalize_times(dest, track_size*2); + image.set_write_splice_position(track, head, 0, 0); +} + +bool _86f_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const +{ + std::error_condition err; + size_t actual; + _86FIMG header; + + // read header + std::tie(err, actual) = read_at(io, 0, &header, sizeof(header)); + if(err || (actual != sizeof(header))) + return false; + + int drivecyl, driveheads; + image.get_maximal_geometry(drivecyl, driveheads); + bool skip_odd = drivecyl < 50; + int imagesides = header.flags & TWO_SIDES ? 2 : 1; + int sides = (imagesides == 2) && (driveheads == 2) ? 2 : 1; + + std::vector<uint32_t> tracklist; + int tracklistsize = header.firsttrackoffs - 8; + tracklist.resize(tracklistsize / 4); + std::tie(err, actual) = read_at(io, 8, &tracklist[0], tracklistsize); + if(err || (actual != tracklistsize)) + return false; + + uint32_t tracklen = 0; + if((header.flags & (TOTAL_BC | EXTRA_BC | RPM_MASK)) != (TOTAL_BC | EXTRA_BC)) { + switch(header.flags & (RPM_MASK | RPM_FAST | TYPE_MASK)) { + case TYPE_DD | RPM_2: + case TYPE_HD | RPM_2: + tracklen = 12750; + break; + case TYPE_DD | RPM_15: + case TYPE_HD | RPM_15: + tracklen = 12687; + break; + case TYPE_DD | RPM_1: + case TYPE_HD | RPM_1: + tracklen = 12625; + break; + case TYPE_DD | RPM_0: + case TYPE_HD | RPM_0: + tracklen = 12500; + break; + case TYPE_DD | RPM_1 | RPM_FAST: + case TYPE_HD | RPM_1 | RPM_FAST: + tracklen = 12376; + break; + case TYPE_DD | RPM_15 | RPM_FAST: + case TYPE_HD | RPM_15 | RPM_FAST: + tracklen = 12315; + break; + case TYPE_DD | RPM_2 | RPM_FAST: + case TYPE_HD | RPM_2 | RPM_FAST: + tracklen = 12254; + break; + + case TYPE_ED | RPM_2: + tracklen = 25500; + break; + case TYPE_ED | RPM_15: + tracklen = 25375; + break; + case TYPE_ED | RPM_1: + tracklen = 25250; + break; + case TYPE_ED | RPM_0: + tracklen = 25000; + break; + case TYPE_ED | RPM_1 | RPM_FAST: + tracklen = 25752; + break; + case TYPE_ED | RPM_15 | RPM_FAST: + tracklen = 24630; + break; + case TYPE_ED | RPM_2 | RPM_FAST: + tracklen = 24509; + break; + } + } + uint32_t trackoff; + int trackinfolen = header.flags & EXTRA_BC ? 10 : 6; + if(skip_odd) + drivecyl *= 2; + std::vector<uint8_t> trackbuf; + std::vector<uint8_t> weakbuf; + int track; + for(track=0; (track < (tracklistsize / 4)) && (track < drivecyl); track++) { + for(int side=0; side < sides; side++) { + trackoff = tracklist[(track * imagesides) + side]; + if(!trackoff) break; + if(!skip_odd || track%2 == 0) { + char trackinfo[10]; + std::tie(err, actual) = read_at(io, trackoff, &trackinfo, trackinfolen); // FIXME: check for errors and premature EOF + if(err || (actual != trackinfolen)) + return false; + uint32_t bitcells = tracklen << 4; + uint32_t index_cell; + if(header.flags & EXTRA_BC) + { + uint32_t extra = *(uint32_t *)(trackinfo + 2); + index_cell = *(uint32_t *)(trackinfo + 6); + if((header.flags & TOTAL_BC) && !tracklen) + bitcells = extra; + else + bitcells += (int32_t)extra; + } + else + index_cell = *(uint32_t *)(trackinfo + 2); + uint32_t fulltracklen = (bitcells >> 3) + (bitcells & 7 ? 1 : 0); + uint8_t *weak = nullptr; + trackbuf.resize(fulltracklen); + std::tie(err, actual) = read_at(io, trackoff + trackinfolen, &trackbuf[0], fulltracklen); + if(err || (actual != fulltracklen)) + return false; + if(header.flags & SURFACE_DESC) + { + weakbuf.resize(fulltracklen); + std::tie(err, actual) = read_at(io, trackoff + trackinfolen + fulltracklen, &weakbuf[0], fulltracklen); + if(err || (actual != fulltracklen)) + return false; + weak = &weakbuf[0]; + } + if(skip_odd) { + generate_track_from_bitstream_with_weak(track/2, side, &trackbuf[0], weak, index_cell, bitcells, image); + } + else { + generate_track_from_bitstream_with_weak(track, side, &trackbuf[0], weak, index_cell, bitcells, image); + } + } + } + if(!trackoff) break; + } + + if(imagesides == 2) + image.set_variant(track > 50 ? floppy_image::DSHD : floppy_image::DSDD); + else + image.set_variant(floppy_image::SSDD); + return true; +} + +/* +bool _86f_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const +{ + return true; +} +*/ +const _86f_format FLOPPY_86F_FORMAT; diff --git a/src/lib/formats/86f_dsk.h b/src/lib/formats/86f_dsk.h new file mode 100644 index 00000000000..0afbe4d65ee --- /dev/null +++ b/src/lib/formats/86f_dsk.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, Carl +/********************************************************************* + + formats/86f_dsk.h + + 86f disk images + +*********************************************************************/ +#ifndef MAME_FORMATS_86F_DSK_H +#define MAME_FORMATS_86F_DSK_H + +#pragma once + +#include "flopimg.h" + +class _86f_format : public floppy_image_format_t +{ +public: + _86f_format(); + + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + //virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const override; + + virtual const char *name() const noexcept override; + virtual const char *description() const noexcept override; + virtual const char *extensions() const noexcept override; + virtual bool supports_save() const noexcept override; + +private: + void generate_track_from_bitstream_with_weak(int track, int head, const uint8_t *trackbuf, const uint8_t *weak, int index_cell, int track_size, floppy_image &image) const; +}; + +extern const _86f_format FLOPPY_86F_FORMAT; + +#endif // MAME_FORMATS_86F_DSK_H diff --git a/src/lib/formats/a26_cas.cpp b/src/lib/formats/a26_cas.cpp index 46522bd50de..c609f922348 100644 --- a/src/lib/formats/a26_cas.cpp +++ b/src/lib/formats/a26_cas.cpp @@ -120,7 +120,7 @@ static int a26_cas_do_work( int16_t **buffer, const uint8_t *bytes ) { return size; } -static int a26_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int a26_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int16_t *p = buffer; return a26_cas_do_work( &p, (const uint8_t *)bytes ); diff --git a/src/lib/formats/abc800i_dsk.cpp b/src/lib/formats/abc800i_dsk.cpp index 1961dd9a9de..9a5a798c886 100644 --- a/src/lib/formats/abc800i_dsk.cpp +++ b/src/lib/formats/abc800i_dsk.cpp @@ -89,11 +89,10 @@ const abc800i_format FLOPPY_ABC800I_FORMAT; int abc800i_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[1]; - size_t actual; - io.read_at(0x810, h, 1, actual); + auto const [err, actual] = read_at(io, 0x810, h, 1); // start of directory - if (h[0] == 0x03) + if (!err && (actual == 1) && (h[0] == 0x03)) return FIFID_SIGN; return 0; diff --git a/src/lib/formats/ace_tap.cpp b/src/lib/formats/ace_tap.cpp index a2fa9fe8b80..9613450e59e 100644 --- a/src/lib/formats/ace_tap.cpp +++ b/src/lib/formats/ace_tap.cpp @@ -135,7 +135,7 @@ static int ace_handle_tap(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int ace_tap_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int ace_tap_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return ace_handle_tap( buffer, bytes ); } diff --git a/src/lib/formats/acorn_dsk.cpp b/src/lib/formats/acorn_dsk.cpp index 42a3aa61bdf..682b6424556 100644 --- a/src/lib/formats/acorn_dsk.cpp +++ b/src/lib/formats/acorn_dsk.cpp @@ -16,6 +16,7 @@ #include "multibyte.h" #include <cstring> +#include <tuple> acorn_ssd_format::acorn_ssd_format() : wd177x_format(formats) @@ -45,25 +46,24 @@ int acorn_ssd_format::find_size(util::random_read &io, uint32_t form_factor, con if (io.length(size)) 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.read_at(0x32800, cat, 8, actual); + read_at(io, 0x32800, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 8) == 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.read_at(0x04610, cat, 8, actual); + read_at(io, 0x04610, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "\x00\x28\x43\x29\x4a\x47\x48\x00", 8) == 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.read_at(0x0960, cat, 8, actual); + read_at(io, 0x0960, cat, 8); // FIXME: check for errors and premature EOF 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 @@ -75,7 +75,7 @@ int acorn_ssd_format::find_size(util::random_read &io, uint32_t form_factor, con } // read sector count from side 0 catalogue - io.read_at(0x100, cat, 8, actual); + read_at(io, 0x100, cat, 8); // FIXME: check for errors and premature EOF sectors0 = get_u16be(&cat[6]) & 0x3ff; LOG_FORMATS("ssd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : ""); @@ -84,11 +84,11 @@ int acorn_ssd_format::find_size(util::random_read &io, uint32_t form_factor, con if (f.head_count == 2) { // read sector count from side 2 catalogue - io.read_at((uint64_t)compute_track_size(f) * f.track_count + 0x100, cat, 8, actual); // sequential + read_at(io, (uint64_t)compute_track_size(f) * f.track_count + 0x100, cat, 8); // sequential sectors2 = get_u16be(&cat[6]) & 0x3ff; // exception case for Acorn CP/M System Disc 1 - io.read_at(0x367ec, cat, 8, actual); + read_at(io, 0x367ec, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "/M ", 4) == 0) sectors2 = get_u16be(&cat[6]) & 0x3ff; @@ -99,7 +99,7 @@ int acorn_ssd_format::find_size(util::random_read &io, uint32_t form_factor, con sectors2 = sectors0; } - if (sectors0 > 0 && sectors2 > 0 && size <= (sectors0 + sectors2) * 256) + if (sectors0 > 0 && sectors2 > 0 && sectors0 % 10 == 0 && sectors2 % 10 == 0 && size <= (sectors0 + sectors2) * 256) return i; } } @@ -192,39 +192,38 @@ int acorn_dsd_format::find_size(util::random_read &io, uint32_t form_factor, con 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.read_at(0x1200, cat, 8, actual); + read_at(io, 0x1200, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 8) == 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.read_at(0x08c10, cat, 8, actual); + read_at(io, 0x08c10, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "\x00\x28\x43\x29\x4a\x47\x48\x00", 8) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // test for FLEX - from System Information Record - io.read_at(0x0226, cat, 2, actual); + read_at(io, 0x0226, cat, 2); // FIXME: check for errors and premature EOF if ((memcmp(cat, "\x4f\x14", 2) == 0 || memcmp(cat, "\x4f\x0a", 2) == 0) && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) return i; // read sector count from side 0 catalogue - io.read_at(0x100, cat, 8, actual); + read_at(io, 0x100, cat, 8); // FIXME: check for errors and premature EOF sectors0 = get_u16be(&cat[6]) & 0x3ff; 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)) { // read sector count from side 2 catalogue - io.read_at(0xb00, cat, 8, actual); // interleaved + read_at(io, 0xb00, cat, 8); // interleaved sectors2 = get_u16be(&cat[6]) & 0x3ff; // exception case for Acorn CP/M System Disc 1 - io.read_at(0x97ec, cat, 8, actual); + read_at(io, 0x97ec, cat, 8); // FIXME: check for errors and premature EOF if (memcmp(cat, "/M ", 4) == 0) sectors2 = get_u16be(&cat[6]) & 0x3ff; @@ -295,12 +294,11 @@ const char *opus_ddos_format::extensions() const noexcept int opus_ddos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - size_t actual; uint8_t cat[8]; uint32_t sectors0, sectors2; // read sector count from side 0 catalogue - io.read_at(0x1000, cat, 8, actual); + read_at(io, 0x1000, cat, 8); // FIXME: check for errors and premature EOF sectors0 = get_u16be(&cat[1]); LOG_FORMATS("ddos: sector count 0: %d %s\n", sectors0, sectors0 % 18 != 0 ? "invalid" : ""); @@ -319,7 +317,7 @@ int opus_ddos_format::find_size(util::random_read &io, uint32_t form_factor, con if (f.head_count == 2) { // read sector count from side 2 catalogue - io.read_at((uint64_t)compute_track_size(f) * f.track_count + 0x1000, cat, 8, actual); // sequential + read_at(io, (uint64_t)compute_track_size(f) * f.track_count + 0x1000, cat, 8); // sequential sectors2 = get_u16be(&cat[1]); LOG_FORMATS("ddos: sector count 2: %d %s\n", sectors2, sectors2 % 18 != 0 ? "invalid" : ""); } @@ -393,25 +391,30 @@ const char *acorn_adfs_old_format::extensions() const noexcept int acorn_adfs_old_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { + std::error_condition err; size_t actual; uint8_t map[3]; uint32_t sectors; uint8_t oldmap[4]; // read sector count from free space map - io.read_at(0xfc, map, 3, actual); + std::tie(err, actual) = read_at(io, 0xfc, map, 3); + if (err || (3 != actual)) + return -1; sectors = get_u24le(map); LOG_FORMATS("adfs_o: sector count %d %s\n", sectors, sectors % 16 != 0 ? "invalid" : ""); // read map identifier - io.read_at(0x201, oldmap, 4, actual); + std::tie(err, actual) = read_at(io, 0x201, oldmap, 4); + if (err || (4 != actual)) + return -1; LOG_FORMATS("adfs_o: map identifier %s %s\n", oldmap, memcmp(oldmap, "Hugo", 4) != 0 ? "invalid" : ""); uint64_t size; if (io.length(size)) return -1; - 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) @@ -429,7 +432,7 @@ int acorn_adfs_old_format::identify(util::random_read &io, uint32_t form_factor, { int type = find_size(io, form_factor, variants); - if(type != -1) + if (type != -1) return FIFID_STRUCT | FIFID_SIZE; return 0; @@ -491,14 +494,19 @@ const char *acorn_adfs_new_format::extensions() const noexcept int acorn_adfs_new_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { + std::error_condition err; size_t actual; uint8_t dform[4]; uint8_t eform[4]; // read map identifiers for D and E formats - io.read_at(0x401, dform, 4, actual); + std::tie(err, actual) = read_at(io, 0x401, dform, 4); + if (err || (4 != actual)) + return -1; LOG_FORMATS("adfs_n: map identifier (D format) %s %s\n", dform, (memcmp(dform, "Hugo", 4) != 0 && memcmp(dform, "Nick", 4) != 0) ? "invalid" : ""); - io.read_at(0x801, eform, 4, actual); + std::tie(err, actual) = read_at(io, 0x801, eform, 4); + if (err || (4 != actual)) + return -1; LOG_FORMATS("adfs_n: map identifier (E format) %s %s\n", eform, memcmp(eform, "Nick", 4) != 0 ? "invalid" : ""); uint64_t size; @@ -585,12 +593,14 @@ int acorn_dos_format::find_size(util::random_read &io, uint32_t form_factor, con if (size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) { // read media type ID from FAT - Acorn DOS = 0xfd - 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; + auto const [err, actual] = read_at(io, 0, &type, 1); + if (!err && (1 == actual)) + { + LOG_FORMATS("dos: 800k media type id %02X %s\n", type, type != 0xfd ? "invalid" : ""); + if (type == 0xfd) + return i; + } } } return -1; @@ -647,14 +657,14 @@ bool opus_ddcpm_format::supports_save() const noexcept int opus_ddcpm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - size_t actual; uint8_t h[8]; - - io.read_at(0, h, 8, actual); + auto const [err, actual] = read_at(io, 0, h, 8); + if (err || (8 != actual)) + return 0; uint64_t size; if (io.length(size)) - return -1; + return 0; if (size == 819200 && memcmp(h, "Slogger ", 8) == 0) return FIFID_SIGN | FIFID_SIZE; @@ -686,8 +696,7 @@ bool opus_ddcpm_format::load(util::random_read &io, uint32_t form_factor, const desc_pc_sector sects[10]; uint8_t sectdata[10*512]; - size_t actual; - io.read_at(head * 80 * spt * 512 + track * spt * 512, sectdata, spt * 512, actual); + /*auto const [err, actual] =*/ read_at(io, head * 80 * spt * 512 + track * spt * 512, sectdata, spt * 512); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { @@ -742,7 +751,7 @@ int cumana_dfs_format::find_size(util::random_read &io, uint32_t form_factor, co if (io.length(size)) return -1; - 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) @@ -750,9 +759,10 @@ int cumana_dfs_format::find_size(util::random_read &io, uint32_t form_factor, co if (size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count) { - size_t actual; uint8_t info; - io.read_at(14, &info, 1, actual); + auto const [err, actual] = read_at(io, 14, &info, 1); + if (err || (actual != 1)) + return -1; if (f.head_count == (util::BIT(info, 6) ? 2 : 1) && f.track_count == (util::BIT(info, 7) ? 80 : 40)) return i; } diff --git a/src/lib/formats/aim_dsk.cpp b/src/lib/formats/aim_dsk.cpp index 88399204f37..c33cab8fb12 100644 --- a/src/lib/formats/aim_dsk.cpp +++ b/src/lib/formats/aim_dsk.cpp @@ -72,8 +72,8 @@ bool aim_format::load(util::random_read &io, uint32_t form_factor, const std::ve bool header = false; // Read track - size_t actual; - io.read_at((heads * track + head) * track_size, &track_data[0], track_size, actual); + /*auto const [err, actual] =*/ read_at(io, (heads * track + head) * track_size, &track_data[0], track_size); + // FIXME: check for error and premature EOF // Find first sector header or index mark for (int offset = 0; offset < track_size; offset += 2) diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index 02f5b636cf5..bab86919cb7 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -320,6 +320,10 @@ #include "guab_dsk.h" #endif +#ifdef HAS_FORMATS_H17D_DSK +#include "h17disk.h" +#endif + #ifdef HAS_FORMATS_H8_CAS #include "h8_cas.h" #endif @@ -576,6 +580,10 @@ #include "rx50_dsk.h" #endif +#ifdef HAS_FORMATS_SAP_DSK +#include "sap_dsk.h" +#endif + #ifdef HAS_FORMATS_SC3000_BIT #include "sc3000_bit.h" #endif @@ -785,6 +793,7 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(fs::PRODOS); #endif #ifdef HAS_FORMATS_AP2_DSK + en.add(FLOPPY_A213S_FORMAT); // ap2_dsk.h en.add(FLOPPY_A216S_DOS_FORMAT); // ap2_dsk.h en.add(FLOPPY_A216S_PRODOS_FORMAT); // ap2_dsk.h en.add(FLOPPY_RWTS18_FORMAT); // ap2_dsk.h @@ -1339,6 +1348,9 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(FLOPPY_THOMSON_525_FORMAT); // thom_dsk.h en.add(FLOPPY_THOMSON_35_FORMAT); // thom_dsk.h #endif +#ifdef HAS_FORMATS_SAP_DSK + en.add(FLOPPY_SAP_FORMAT); +#endif en.category("Texas Instruments"); #ifdef HAS_FORMATS_TI99_DSK @@ -1510,7 +1522,7 @@ void mame_formats_full_list(mame_formats_enumerator &en) en.add(vtech1_cassette_formats); // vt_cas.h en.add(vtech2_cassette_formats); // vt_cas.h #endif -#ifdef HAS_FORMATS_VT_DSJ +#ifdef HAS_FORMATS_VT_DSK en.add(FLOPPY_VTECH_BIN_FORMAT); // vt_dsk.h en.add(FLOPPY_VTECH_DSK_FORMAT); // vt_dsk.h #endif @@ -1522,4 +1534,9 @@ void mame_formats_full_list(mame_formats_enumerator &en) #ifdef HAS_FORMATS_X07_CAS en.add(x07_cassette_formats); // x07_cas.h #endif + + en.category("Heath"); +#ifdef HAS_FORMATS_H17D_DSK + en.add(FLOPPY_H17D_FORMAT); // h17disk.h +#endif } diff --git a/src/lib/formats/ami_dsk.cpp b/src/lib/formats/ami_dsk.cpp index 6ad9145c7d8..d4c567050c8 100644 --- a/src/lib/formats/ami_dsk.cpp +++ b/src/lib/formats/ami_dsk.cpp @@ -81,8 +81,9 @@ bool adf_format::load(util::random_read &io, uint32_t form_factor, const std::ve image.set_variant(floppy_image::DSDD); 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); + auto const [err, actual] = read_at(io, (track*2 + side)*512*11, sectdata, 512*11); + if (err || (512*11 != actual)) + return false; generate_track(amiga_11, track, side, sectors, 11, 100000, image); } } @@ -90,8 +91,9 @@ bool adf_format::load(util::random_read &io, uint32_t form_factor, const std::ve image.set_variant(floppy_image::DSHD); 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); + auto const [err, actual] = read_at(io, (track*2 + side)*512*22, sectdata, 512*22); + if (err || (512*22 != actual)) + return false; generate_track(amiga_22, track, side, sectors, 22, 200000, image); } } @@ -151,8 +153,8 @@ bool adf_format::save(util::random_read_write &io, const std::vector<uint32_t> & *dest++ = val; } - size_t actual; - io.write_at((track*2 + side) * data_track_size, sectdata, data_track_size, actual); + // FIXME: check for errors + /*auto const [err, actual] =*/ write_at(io, (track*2 + side) * data_track_size, sectdata, data_track_size); } } } diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp index 557800dcec2..1880ad7bd23 100644 --- a/src/lib/formats/ap2_dsk.cpp +++ b/src/lib/formats/ap2_dsk.cpp @@ -18,6 +18,128 @@ #include <cstdlib> #include <cstring> +static const uint8_t translate5[] = { + 0xab, 0xad, 0xae, 0xaf, 0xb5, 0xb6, 0xb7, 0xba, + 0xbb, 0xbd, 0xbe, 0xbf, 0xd6, 0xd7, 0xda, 0xdb, + 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xed, 0xee, 0xef, + 0xf5, 0xf6, 0xf7, 0xfa, 0xfb, 0xfd, 0xfe, 0xff, +}; + +a2_13sect_format::a2_13sect_format() : floppy_image_format_t() +{ +} + +int a2_13sect_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint64_t size; + if (io.length(size)) + return 0; + + if (size != APPLE2_STD_TRACK_COUNT * 13 * APPLE2_SECTOR_SIZE) + return 0; + + return FIFID_SIZE; +} + +bool a2_13sect_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const +{ + uint64_t size; + if (io.length(size)) + return false; + + image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + + int tracks = size / 13 / APPLE2_SECTOR_SIZE; + + for(int track = 0; track < tracks; track++) { + std::vector<uint32_t> track_data; + uint8_t sector_data[APPLE2_SECTOR_SIZE * 13]; + + auto const [err, actual] = read_at( + io, track * sizeof sector_data, sector_data, sizeof sector_data); + if (err || actual != sizeof sector_data) + return false; + + for(int i=0; i<13; i++) { + int sector = (i * 10) % 13; + + // write inter-sector padding + for(int j=0; j<40; j++) + raw_w(track_data, 9, 0x1fe); + raw_w(track_data, 8, 0xff); + + // write sector address + raw_w(track_data, 24, 0xd5aab5); + raw_w(track_data, 16, gcr4_encode(0xfe)); + raw_w(track_data, 16, gcr4_encode(track)); + raw_w(track_data, 16, gcr4_encode(sector)); + raw_w(track_data, 16, gcr4_encode(0xfe ^ track ^ sector)); + raw_w(track_data, 24, 0xdeaaeb); + + // write intra-sector padding + for(int j=0; j<11; j++) + raw_w(track_data, 9, 0x1fe); + + // write sector data + raw_w(track_data, 24, 0xd5aaad); + + uint8_t pval = 0x00; + auto write_data_byte = [&track_data, &pval](uint8_t nval) { + raw_w(track_data, 8, translate5[nval ^ pval]); + pval = nval; + }; + + const uint8_t *sdata = sector_data + APPLE2_SECTOR_SIZE * sector; + + // write 154 bytes encoding bits 2-0 + write_data_byte(sdata[255] & 7); + for (int k=2; k>-1; k--) + for (int j=0; j<51; j++) + write_data_byte( + (sdata[j*5+k] & 7) << 2 + | ((sdata[j*5+3] >> (2-k)) & 1) << 1 + | ((sdata[j*5+4] >> (2-k)) & 1)); + + // write 256 bytes encoding bits 7-3 + for (int k=0; k<5; k++) + for (int j=50; j>-1; j--) + write_data_byte(sdata[j*5+k] >> 3); + write_data_byte(sdata[255] >> 3); + + raw_w(track_data, 8, translate5[pval]); + raw_w(track_data, 24, 0xdeaaeb); + raw_w(track_data, 8, 0xff); + } + + generate_track_from_levels(track, 0, track_data, 0, image); + } + + return true; +} + + +const char *a2_13sect_format::name() const noexcept +{ + return "a2_13sect"; +} + +const char *a2_13sect_format::description() const noexcept +{ + return "Apple II 13-sector d13 image"; +} + +const char *a2_13sect_format::extensions() const noexcept +{ + return "d13"; +} + +bool a2_13sect_format::supports_save() const noexcept +{ + return false; +} + +const a2_13sect_format FLOPPY_A213S_FORMAT; + static const uint8_t translate6[0x40] = { 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, @@ -96,16 +218,17 @@ int a2_16sect_format::identify(util::random_read &io, uint32_t form_factor, cons if (io.length(size)) return 0; - //uint32_t expected_size = 35 * 16 * 256; - uint32_t expected_size = APPLE2_TRACK_COUNT * 16 * 256; - // check standard size plus some oddball sizes in our softlist - if ((size != expected_size) && (size != 35 * 16 * 256) && (size != 143403) && (size != 143363) && (size != 143358)) + if ( + size != APPLE2_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE + && size != APPLE2_STD_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE + && size != 143403 && size != 143363 && size != 143358 && size != 143195 + ) { return 0; } - uint8_t sector_data[256*2]; + uint8_t sector_data[APPLE2_SECTOR_SIZE*2]; static const unsigned char pascal_block1[4] = { 0x08, 0xa5, 0x0f, 0x29 }; static const unsigned char pascal2_block1[4] = { 0xff, 0xa2, 0x00, 0x8e }; static const unsigned char dos33_block1[4] = { 0xa2, 0x02, 0x8e, 0x52 }; @@ -114,8 +237,9 @@ int a2_16sect_format::identify(util::random_read &io, uint32_t form_factor, cons 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 }; - size_t actual; - io.read_at(0, sector_data, 256*2, actual); + auto const [err, actual] = read_at(io, 0, sector_data, sizeof sector_data); + if (err || actual != sizeof sector_data) + return 0; bool prodos_order = false; // check ProDOS boot block @@ -181,17 +305,20 @@ bool a2_16sect_format::load(util::random_read &io, uint32_t form_factor, const s image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); - int tracks = (size == (40 * 16 * 256)) ? 40 : 35; + int tracks = (size == (APPLE2_TRACK_COUNT * 16 * APPLE2_SECTOR_SIZE)) ? APPLE2_TRACK_COUNT : APPLE2_STD_TRACK_COUNT; int fpos = 0; for(int track=0; track < tracks; track++) { std::vector<uint32_t> track_data; - uint8_t sector_data[256*16]; + uint8_t sector_data[APPLE2_SECTOR_SIZE*16]; - size_t actual; - io.read_at(fpos, sector_data, 256*16, actual); + auto const [err, actual] = read_at(io, fpos, sector_data, sizeof sector_data); + // Some supported images have oddball sizes, where the last track is incomplete. + // Skip the `actual` check to avoid rejecting them. + if (err /* || actual != sizeof sector_data */) + return false; - fpos += 256*16; + fpos += APPLE2_SECTOR_SIZE*16; for(int i=0; i<49; i++) raw_w(track_data, 10, 0x3fc); for(int i=0; i<16; i++) { @@ -206,7 +333,7 @@ bool a2_16sect_format::load(util::random_read &io, uint32_t form_factor, const s sector = dos_skewing[i]; } - const uint8_t *sdata = sector_data + 256 * sector; + const uint8_t *sdata = sector_data + APPLE2_SECTOR_SIZE * sector; for(int j=0; j<20; j++) raw_w(track_data, 10, 0x3fc); raw_w(track_data, 8, 0xff); @@ -269,212 +396,215 @@ uint8_t a2_16sect_format::gb(const std::vector<bool> &buf, int &pos, int &wrap) return v; } -//#define VERBOSE_SAVE - bool a2_16sect_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - int g_tracks, g_heads; - int visualgrid[16][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below - -// lenient addr check: if unset, only accept an addr mark if the checksum was good -// if set, accept an addr mark if the track and sector values are both sane -#undef LENIENT_ADDR_CHECK -// if set, use the old, not as robust logic for choosing which copy of a decoded sector to write -// to the resulting image if the sector has a bad checksum and/or postamble -#undef USE_OLD_BEST_SECTOR_PRIORITY -// nothing found -#define NOTFOUND 0 -// address mark was found -#define ADDRFOUND 1 -// address checksum is good -#define ADDRGOOD 2 -// data mark was found (requires addrfound and sane values) -#define DATAFOUND 4 -// data checksum is good -#define DATAGOOD 8 -// data postamble is good -#define DATAPOST 16 - for (auto & elem : visualgrid) { - for (int j = 0; j < APPLE2_TRACK_COUNT; j++) { - elem[j] = 0; - } + int g_tracks, g_heads; + int visualgrid[16][APPLE2_TRACK_COUNT]; // visualizer grid, cleared/initialized below + + constexpr bool VERBOSE_SAVE = false; + + // if false, only accept an addr mark if the checksum was good + // if true, accept an addr mark if the track and sector values are both sane + constexpr bool LENIENT_ADDR_CHECK = false; + + // if true, use the old, not as robust logic for choosing which copy of a decoded sector to write + // to the resulting image if the sector has a bad checksum and/or postamble + constexpr bool USE_OLD_BEST_SECTOR_PRIORITY = false; + + // nothing found + constexpr int NOTFOUND = 0; + // address mark was found + constexpr int ADDRFOUND = 1; + // address checksum is good + constexpr int ADDRGOOD = 2; + // data mark was found (requires addrfound and sane values) + constexpr int DATAFOUND = 4; + // data checksum is good + constexpr int DATAGOOD = 8; + // data postamble is good + constexpr int DATAPOST = 16; + + for (auto & elem : visualgrid) { + for (int j = 0; j < APPLE2_TRACK_COUNT; j++) { + elem[j] = NOTFOUND; } - image.get_actual_geometry(g_tracks, g_heads); + } + image.get_actual_geometry(g_tracks, g_heads); - int head = 0; + int head = 0; - int pos_data = 0; + int pos_data = 0; - for(int track=0; track < g_tracks; track++) { - uint8_t sectdata[(256)*16]; - memset(sectdata, 0, sizeof(sectdata)); - int nsect = 16; - #ifdef VERBOSE_SAVE - fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from track %d...", track); - #endif - auto buf = generate_bitstream_from_track(track, head, 3915, image); - #ifdef VERBOSE_SAVE - fprintf(stderr,"done.\n"); - #endif - int pos = 0; - int wrap = 0; - int hb = 0; - int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3 - for(;;) { - uint8_t v = gb(buf, pos, wrap); - if(v == 0xff) { + for(int track=0; track < g_tracks; track++) { + uint8_t sectdata[APPLE2_SECTOR_SIZE*16]; + memset(sectdata, 0, sizeof(sectdata)); + int nsect = 16; + if(VERBOSE_SAVE) { + fprintf(stderr,"DEBUG: a2_16sect_format::save() about to generate bitstream from track %d...", track); + } + auto buf = generate_bitstream_from_track(track, head, 3915, image); + if(VERBOSE_SAVE) { + fprintf(stderr,"done.\n"); + } + int pos = 0; + int wrap = 0; + int hb = 0; + int dosver = 0; // apple dos version; 0 = >=3.3, 1 = <3.3 + for(;;) { + uint8_t v = gb(buf, pos, wrap); + if(v == 0xff) { + hb = 1; + } + else if(hb == 1 && v == 0xd5){ + hb = 2; + } + else if(hb == 2 && v == 0xaa) { + hb = 3; + } + else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec + hb = 4; + if (v == 0xab) dosver = 1; + } + else + hb = 0; + + if(hb == 4) { + uint8_t h[11]; + for(auto & elem : h) + elem = gb(buf, pos, wrap); + //uint8_t v2 = gcr6bw_tb[h[2]]; + uint8_t vl = gcr4_decode(h[0],h[1]); + uint8_t tr = gcr4_decode(h[2],h[3]); + uint8_t se = gcr4_decode(h[4],h[5]); + uint8_t chk = gcr4_decode(h[6],h[7]); + if(VERBOSE_SAVE) { + uint32_t post = get_u24be(&h[8]); + printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", + vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD"); + } + // sanity check + if (tr == track && se < nsect) { + visualgrid[se][track] |= ADDRFOUND; + visualgrid[se][track] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0; + + if (visualgrid[se][track] & (LENIENT_ADDR_CHECK ? ADDRFOUND : ADDRGOOD)) { + int opos = pos; + int owrap = wrap; + hb = 0; + for(int i=0; i<20 && hb != 4; i++) { + v = gb(buf, pos, wrap); + if(v == 0xff) hb = 1; - } - else if(hb == 1 && v == 0xd5){ + else if(hb == 1 && v == 0xd5) hb = 2; - } - else if(hb == 2 && v == 0xaa) { + else if(hb == 2 && v == 0xaa) hb = 3; - } - else if(hb == 3 && ((v == 0x96) || (v == 0xab))) { // 0x96 = dos 3.3/16sec, 0xab = dos 3.21 and below/13sec + else if(hb == 3 && v == 0xad) hb = 4; - if (v == 0xab) dosver = 1; - } else hb = 0; + } + if((hb == 4)&&(dosver == 0)) { + visualgrid[se][track] |= DATAFOUND; + uint8_t *dest; + uint8_t data[0x157]; + uint32_t dpost = 0; + uint8_t c = 0; + + if (m_prodos_order) + { + dest = sectdata+APPLE2_SECTOR_SIZE*prodos_skewing[se]; + } + else + { + dest = sectdata+APPLE2_SECTOR_SIZE*dos_skewing[se]; + } - if(hb == 4) { - uint8_t h[11]; - for(auto & elem : h) - elem = gb(buf, pos, wrap); - //uint8_t v2 = gcr6bw_tb[h[2]]; - uint8_t vl = gcr4_decode(h[0],h[1]); - uint8_t tr = gcr4_decode(h[2],h[3]); - uint8_t se = gcr4_decode(h[4],h[5]); - uint8_t chk = gcr4_decode(h[6],h[7]); - #ifdef VERBOSE_SAVE - uint32_t post = get_u24be(&h[8]); - printf("Address Mark:\tVolume %d, Track %d, Sector %2d, Checksum %02X: %s, Postamble %03X: %s\n", vl, tr, se, chk, (chk ^ vl ^ tr ^ se)==0?"OK":"BAD", post, (post&0xFFFF00)==0xDEAA00?"OK":"BAD"); - #endif - // sanity check - if (tr == track && se < nsect) { - visualgrid[se][track] |= ADDRFOUND; - visualgrid[se][track] |= ((chk ^ vl ^ tr ^ se)==0)?ADDRGOOD:0; -#ifdef LENIENT_ADDR_CHECK - if ((visualgrid[se][track] & ADDRFOUND) == ADDRFOUND) { -#else - if ((visualgrid[se][track] & ADDRGOOD) == ADDRGOOD) { -#endif - int opos = pos; - int owrap = wrap; - hb = 0; - for(int i=0; i<20 && hb != 4; i++) { - v = gb(buf, pos, wrap); - if(v == 0xff) - hb = 1; - else if(hb == 1 && v == 0xd5) - hb = 2; - else if(hb == 2 && v == 0xaa) - hb = 3; - else if(hb == 3 && v == 0xad) - hb = 4; - else - hb = 0; - } - if((hb == 4)&&(dosver == 0)) { - visualgrid[se][track] |= DATAFOUND; - uint8_t *dest; - uint8_t data[0x157]; - uint32_t dpost = 0; - uint8_t c = 0; - - if (m_prodos_order) - { - dest = sectdata+(256)*prodos_skewing[se]; - } - else - { - dest = sectdata+(256)*dos_skewing[se]; - } - - // first read in sector and decode to 6bit form - for(int i=0; i<0x156; i++) { - data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ^ c; - c = data[i]; - // printf("%02x ", c); - // if (((i&0xf)+1)==0x10) printf("\n"); - } - // read the checksum byte - data[0x156] = gcr6bw_tb[gb(buf,pos,wrap)]; - // now read the postamble bytes - for(int i=0; i<3; i++) { - dpost <<= 8; - dpost |= gb(buf, pos, wrap); - } - // next combine in the upper 2 bits of each byte - uint8_t bit_swap[4] = { 0, 2, 1, 3 }; - for(int i=0; i<0x56; i++) - data[i+0x056] = data[i+0x056]<<2 | bit_swap[data[i]&3]; - for(int i=0; i<0x56; i++) - data[i+0x0ac] = data[i+0x0ac]<<2 | bit_swap[(data[i]>>2)&3]; - for(int i=0; i<0x54; i++) - data[i+0x102] = data[i+0x102]<<2 | bit_swap[(data[i]>>4)&3]; - // now decode it into 256 bytes - // but only write it if the bitfield of the track shows datagood is NOT set. - // if it is set we don't want to overwrite a guaranteed good read with a bad one - // if past read had a bad checksum or bad postamble... -#ifndef USE_OLD_BEST_SECTOR_PRIORITY - if (((visualgrid[se][track]&DATAGOOD)==0)||((visualgrid[se][track]&DATAPOST)==0)) { - // if the current read is good, and postamble is good, write it in, no matter what. - // if the current read is good and the current postamble is bad, write it in unless the postamble was good before - // if the current read is bad and the current postamble is good and the previous read had neither good, write it in - // if the current read isn't good and neither is the postamble but nothing better - // has been written before, write it anyway. - if ( ((data[0x156] == c) && (dpost&0xFFFF00)==0xDEAA00) || - (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track]&DATAPOST)==0)) || - (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) || - (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) - ) { - for(int i=0x56; i<0x156; i++) { - uint8_t dv = data[i]; - *dest++ = dv; - } - } - } -#else - if ((visualgrid[se][track]&DATAGOOD)==0) { - for(int i=0x56; i<0x156; i++) { - uint8_t dv = data[i]; - *dest++ = dv; - } - } -#endif - // do some checking - #ifdef VERBOSE_SAVE - if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00) - fprintf(stderr,"Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n", data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD"); - #endif - if (data[0x156] == c) visualgrid[se][track] |= DATAGOOD; - if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track] |= DATAPOST; - } else if ((hb == 4)&&(dosver == 1)) { - fprintf(stderr,"ERROR: We don't handle dos sectors below 3.3 yet!\n"); - } else { - pos = opos; - wrap = owrap; + // first read in sector and decode to 6bit form + for(int i=0; i<0x156; i++) { + data[i] = gcr6bw_tb[gb(buf, pos, wrap)] ^ c; + c = data[i]; + // printf("%02x ", c); + // if (((i&0xf)+1)==0x10) printf("\n"); + } + // read the checksum byte + data[0x156] = gcr6bw_tb[gb(buf,pos,wrap)]; + // now read the postamble bytes + for(int i=0; i<3; i++) { + dpost <<= 8; + dpost |= gb(buf, pos, wrap); + } + // next combine in the upper 2 bits of each byte + uint8_t bit_swap[4] = { 0, 2, 1, 3 }; + for(int i=0; i<0x56; i++) + data[i+0x056] = data[i+0x056]<<2 | bit_swap[data[i]&3]; + for(int i=0; i<0x56; i++) + data[i+0x0ac] = data[i+0x0ac]<<2 | bit_swap[(data[i]>>2)&3]; + for(int i=0; i<0x54; i++) + data[i+0x102] = data[i+0x102]<<2 | bit_swap[(data[i]>>4)&3]; + // now decode it into 256 bytes + // but only write it if the bitfield of the track shows datagood is NOT set. + // if it is set we don't want to overwrite a guaranteed good read with a bad one + // if past read had a bad checksum or bad postamble... + if(USE_OLD_BEST_SECTOR_PRIORITY) { + if ((visualgrid[se][track]&DATAGOOD)==0) { + for(int i=0x56; i<0x156; i++) { + uint8_t dv = data[i]; + *dest++ = dv; + } + } + } else { + if (((visualgrid[se][track]&DATAGOOD)==0)||((visualgrid[se][track]&DATAPOST)==0)) { + // if the current read is good, and postamble is good, write it in, no matter what. + // if the current read is good and the current postamble is bad, write it in unless the postamble was good before + // if the current read is bad and the current postamble is good and the previous read had neither good, write it in + // if the current read isn't good and neither is the postamble but nothing better + // has been written before, write it anyway. + if ( ((data[0x156] == c) && (dpost&0xFFFF00)==0xDEAA00) || + (((data[0x156] == c) && (dpost&0xFFFF00)!=0xDEAA00) && ((visualgrid[se][track]&DATAPOST)==0)) || + (((data[0x156] != c) && (dpost&0xFFFF00)==0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) || + (((data[0x156] != c) && (dpost&0xFFFF00)!=0xDEAA00) && (((visualgrid[se][track]&DATAGOOD)==0)&&(visualgrid[se][track]&DATAPOST)==0)) + ) { + for(int i=0x56; i<0x156; i++) { + uint8_t dv = data[i]; + *dest++ = dv; } } } - hb = 0; + } + // do some checking + if(VERBOSE_SAVE) { + if ((data[0x156] != c) || (dpost&0xFFFF00)!=0xDEAA00) + fprintf(stderr,"Data Mark:\tChecksum xpctd %d found %d: %s, Postamble %03X: %s\n", + data[0x156], c, (data[0x156]==c)?"OK":"BAD", dpost, (dpost&0xFFFF00)==0xDEAA00?"OK":"BAD"); + } + if (data[0x156] == c) visualgrid[se][track] |= DATAGOOD; + if ((dpost&0xFFFF00)==0xDEAA00) visualgrid[se][track] |= DATAPOST; + } else if ((hb == 4)&&(dosver == 1)) { + fprintf(stderr,"ERROR: We don't handle dos sectors below 3.3 yet!\n"); + } else { + pos = opos; + wrap = owrap; } - if(wrap) - break; + } } - for(int i=0; i<nsect; i++) { - //if(nsect>0) printf("t%d,", track); - uint8_t const *const data = sectdata + (256)*i; - size_t actual; - io.write_at(pos_data, data, 256, actual); - pos_data += 256; - } - //printf("\n"); + hb = 0; + } + if(wrap) + break; } - // display a little table of which sectors decoded ok - #ifdef VERBOSE_SAVE + for(int i=0; i<nsect; i++) { + //if(nsect>0) printf("t%d,", track); + uint8_t const *const data = sectdata + APPLE2_SECTOR_SIZE*i; + auto const [err, actual] = write_at(io, pos_data, data, APPLE2_SECTOR_SIZE); + if (err || actual != APPLE2_SECTOR_SIZE) + return false; + pos_data += APPLE2_SECTOR_SIZE; + } + //printf("\n"); + } + // display a little table of which sectors decoded ok + if(VERBOSE_SAVE) { int total_good = 0; for (int j = 0; j < APPLE2_TRACK_COUNT; j++) { printf("T%2d: ",j); @@ -491,9 +621,9 @@ bool a2_16sect_format::save(util::random_read_write &io, const std::vector<uint3 printf("\n"); } printf("Total Good Sectors: %d\n", total_good); - #endif + } - return true; + return true; } const a2_16sect_dos_format FLOPPY_A216S_DOS_FORMAT; @@ -796,8 +926,7 @@ bool a2_rwts18_format::save(util::random_read_write &io, const std::vector<uint3 for(int i=0; i<nsect; i++) { //if(nsect>0) printf("t%d,", track); uint8_t const *const data = sectdata + (256)*i; - size_t actual; - io.write_at(pos_data, data, 256, actual); + /*auto const [err, actual] =*/ write_at(io, pos_data, data, 256); // FIXME: check for errors pos_data += 256; } @@ -978,8 +1107,7 @@ bool a2_rwts18_format::save(util::random_read_write &io, const std::vector<uint3 for(int i=0; i<nsect; i++) { //if(nsect>0) printf("t%d,", track); uint8_t const *const data = sectdata + (256)*i; - size_t actual; - io.write_at(pos_data, data, 256, actual); + /*auto const [err, actual] =*/ write_at(io, pos_data, data, 256); // FIXME: check for errors pos_data += 256; } //printf("\n"); @@ -1048,14 +1176,12 @@ bool a2_edd_format::load(util::random_read &io, uint32_t form_factor, const std: { uint8_t nibble[16384], stream[16384]; int npos[16384]; + static const size_t img_size = 2'244'608; - std::unique_ptr<uint8_t []> img(new (std::nothrow) uint8_t[2244608]); - if (!img) + auto [err, img, actual] = read_at(io, 0, img_size); + if(err || actual != img_size) return false; - size_t actual; - io.read_at(0, img.get(), 2244608, actual); - for(int i=0; i<137; i++) { uint8_t const *const trk = &img[16384*i]; int pos = 0; @@ -1286,16 +1412,18 @@ bool a2_nib_format::load(util::random_read &io, uint32_t form_factor, const std: if (size != expected_size_35t && size != expected_size_40t) return false; - const auto nr_tracks = size == expected_size_35t? 35 : 40; + const auto nr_tracks = size / nibbles_per_track; std::vector<uint8_t> nibbles(nibbles_per_track); for (unsigned track = 0; track < nr_tracks; ++track) { - size_t actual; - io.read_at(track * nibbles_per_track, &nibbles[0], nibbles_per_track, actual); + auto const [err, actual] = read_at(io, track * nibbles_per_track, &nibbles[0], nibbles_per_track); + if (err || actual != nibbles_per_track) + return false; + auto levels = generate_levels_from_nibbles(nibbles); - generate_track_from_levels(track, 0, - levels, - 0, image); + if (!levels.empty()) { + generate_track_from_levels(track, 0, levels, 0, image); + } } image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); diff --git a/src/lib/formats/ap2_dsk.h b/src/lib/formats/ap2_dsk.h index cbeea73f2d3..33117ecbd84 100644 --- a/src/lib/formats/ap2_dsk.h +++ b/src/lib/formats/ap2_dsk.h @@ -21,14 +21,30 @@ ***************************************************************************/ -#define APPLE2_NIBBLE_SIZE 416 -#define APPLE2_SMALL_NIBBLE_SIZE 374 -#define APPLE2_STD_TRACK_COUNT 35 -#define APPLE2_TRACK_COUNT 40 -#define APPLE2_SECTOR_COUNT 16 -#define APPLE2_SECTOR_SIZE 256 +constexpr int APPLE2_STD_TRACK_COUNT = 35; +constexpr int APPLE2_TRACK_COUNT = 40; +constexpr int APPLE2_SECTOR_SIZE = 256; /**************************************************************************/ +class a2_13sect_format : public floppy_image_format_t +{ +public: + a2_13sect_format(); + + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + + virtual const char *name() const noexcept override; + virtual const char *description() const noexcept override; + virtual const char *extensions() const noexcept override; + virtual bool supports_save() const noexcept override; + +private: + static uint8_t gb(const std::vector<bool> &buf, int &pos, int &wrap); +}; + +extern const a2_13sect_format FLOPPY_A213S_FORMAT; + class a2_16sect_format : public floppy_image_format_t { public: @@ -126,8 +142,8 @@ public: private: static constexpr size_t nibbles_per_track = 0x1a00; static constexpr size_t min_sync_bytes = 4; - static constexpr auto expected_size_35t = 35 * nibbles_per_track; - static constexpr auto expected_size_40t = 40 * nibbles_per_track; + static constexpr auto expected_size_35t = APPLE2_STD_TRACK_COUNT * nibbles_per_track; + static constexpr auto expected_size_40t = APPLE2_TRACK_COUNT * nibbles_per_track; static std::vector<uint32_t> generate_levels_from_nibbles(const std::vector<uint8_t>& nibbles); }; diff --git a/src/lib/formats/ap_dsk35.cpp b/src/lib/formats/ap_dsk35.cpp index b4a82e5ff56..4096215c35f 100644 --- a/src/lib/formats/ap_dsk35.cpp +++ b/src/lib/formats/ap_dsk35.cpp @@ -142,27 +142,26 @@ int dc42_format::identify(util::random_read &io, uint32_t form_factor, const std return 0; uint8_t h[0x54]; - size_t actual; - io.read_at(0, h, 0x54, actual); - uint32_t dsize = get_u32be(&h[0x40]); - uint32_t tsize = get_u32be(&h[0x44]); + auto const [err, actual] = read_at(io, 0, h, 0x54); + if (err || (0x54 != actual)) + return 0; - uint8_t encoding = h[0x50]; - uint8_t format = h[0x51]; + uint32_t const dsize = get_u32be(&h[0x40]); + uint32_t const tsize = get_u32be(&h[0x44]); + + uint8_t const encoding = h[0x50]; + uint8_t const format = h[0x51]; // if it's a 1.44MB DC42 image, reject it so the generic PC MFM handler picks it up if ((encoding == 0x03) && (format == 0x02)) - { return 0; - } return (size == 0x54+tsize+dsize && h[0] < 64 && h[0x52] == 1 && h[0x53] == 0) ? FIFID_STRUCT : 0; } bool dc42_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; uint8_t h[0x54]; - io.read_at(0, h, 0x54, actual); + read_at(io, 0, h, 0x54); // FIXME: check for errors and premature EOF int dsize = get_u32be(&h[0x40]); int tsize = get_u32be(&h[0x44]); @@ -218,14 +217,14 @@ bool dc42_format::load(util::random_read &io, uint32_t form_factor, const std::v sectors[si].sector = i; sectors[si].info = format; if(tsize) { - io.read_at(pos_tag, data, 12, actual); + read_at(io, pos_tag, data, 12); // FIXME: check for errors and premature EOF sectors[si].tag = data; pos_tag += 12; } else { sectors[si].tag = nullptr; } sectors[si].data = data+12; - io.read_at(pos_data, data+12, 512, actual); + read_at(io, pos_data, data+12, 512); // FIXME: check for errors and premature EOF pos_data += 512; si = (si + 2) % ns; if(si == 0) @@ -279,9 +278,8 @@ bool dc42_format::save(util::random_read_write &io, const std::vector<uint32_t> for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - size_t actual; - io.write_at(pos_tag, &sdata[0], 12, actual); - io.write_at(pos_data, &sdata[12], 512, actual); + write_at(io, pos_tag, &sdata[0], 12); // FIXME: check for errors + write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors pos_tag += 12; pos_data += 512; if(track || head || i) @@ -294,8 +292,7 @@ bool dc42_format::save(util::random_read_write &io, const std::vector<uint32_t> put_u32be(&h[0x48], dchk); put_u32be(&h[0x4c], tchk); - size_t actual; - io.write_at(0, h, 0x54, actual); + write_at(io, 0, h, 0x54); // FIXME: check for errors return true; } @@ -340,14 +337,13 @@ int apple_gcr_format::identify(util::random_read &io, uint32_t form_factor, cons bool apple_gcr_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; desc_gcr_sector sectors[12]; uint8_t sdata[512*12]; int pos_data = 0; uint8_t header[64]; - io.read_at(0, header, 64, actual); + read_at(io, 0, header, 64); // FIXME: check for errors and premature EOF uint64_t size; if(io.length(size)) @@ -361,7 +357,7 @@ bool apple_gcr_format::load(util::random_read &io, uint32_t form_factor, const s for(int track=0; track < 80; track++) { for(int head=0; head < head_count; head++) { int ns = 12 - (track/16); - io.read_at(pos_data, sdata, 512*ns, actual); + read_at(io, pos_data, sdata, 512*ns); // FIXME: check for errors and premature EOF pos_data += 512*ns; int si = 0; @@ -398,8 +394,7 @@ bool apple_gcr_format::save(util::random_read_write &io, const std::vector<uint3 for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - size_t actual; - io.write_at(pos_data, &sdata[12], 512, actual); + /*auto const [err, actual] =*/ write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors pos_data += 512; } } @@ -438,15 +433,19 @@ bool apple_2mg_format::supports_save() const noexcept int apple_2mg_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t signature[4]; - size_t actual; - io.read_at(0, signature, 4, actual); - if (!strncmp(reinterpret_cast<char *>(signature), "2IMG", 4)) + auto const [err, actual] = read_at(io, 0, signature, 4); + if (err || (4 != actual)) + { + return 0; + } + + if (!memcmp(signature, "2IMG", 4)) { return FIFID_SIGN; } // Bernie ][ The Rescue wrote 2MGs with the signature byte-flipped, other fields are valid - if (!strncmp(reinterpret_cast<char *>(signature), "GMI2", 4)) + if (!memcmp(signature, "GMI2", 4)) { return FIFID_SIGN; } @@ -456,10 +455,9 @@ int apple_2mg_format::identify(util::random_read &io, uint32_t form_factor, cons bool apple_2mg_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; desc_gcr_sector sectors[12]; uint8_t sdata[512*12], header[64]; - io.read_at(0, header, 64, actual); + read_at(io, 0, header, 64); // FIXME: check for errors and premature EOF uint32_t blocks = get_u32le(&header[0x14]); uint32_t pos_data = get_u32le(&header[0x18]); @@ -471,7 +469,7 @@ bool apple_2mg_format::load(util::random_read &io, uint32_t form_factor, const s for(int track=0; track < 80; track++) { for(int head=0; head < 2; head++) { int ns = 12 - (track/16); - io.read_at(pos_data, sdata, 512*ns, actual); + read_at(io, pos_data, sdata, 512*ns); // FIXME: check for errors and premature EOF pos_data += 512*ns; int si = 0; @@ -494,8 +492,6 @@ bool apple_2mg_format::load(util::random_read &io, uint32_t form_factor, const s bool apple_2mg_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - size_t actual; - uint8_t header[0x40]; int pos_data = 0x40; @@ -516,7 +512,7 @@ bool apple_2mg_format::save(util::random_read_write &io, const std::vector<uint3 header[0x18] = 0x40; // bytes of disk data header[0x1c] = 0x00; header[0x1d] = 0x80; header[0x1e] = 0x0c; // 0xC8000 (819200) - io.write_at(0, header, 0x40, actual); + write_at(io, 0, header, 0x40); // FIXME: check for errors for(int track=0; track < 80; track++) { for(int head=0; head < 2; head++) { @@ -524,7 +520,7 @@ bool apple_2mg_format::save(util::random_read_write &io, const std::vector<uint3 for(unsigned int i=0; i < sectors.size(); i++) { auto &sdata = sectors[i]; sdata.resize(512+12); - io.write_at(pos_data, &sdata[12], 512, actual); + write_at(io, pos_data, &sdata[12], 512); // FIXME: check for errors pos_data += 512; } } diff --git a/src/lib/formats/apd_dsk.cpp b/src/lib/formats/apd_dsk.cpp index c1319e43cf4..55d722bdf38 100644 --- a/src/lib/formats/apd_dsk.cpp +++ b/src/lib/formats/apd_dsk.cpp @@ -101,8 +101,9 @@ int apd_format::identify(util::random_read &io, uint32_t form_factor, const std: return 0; std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [ioerr, actual] = read_at(io, 0, &img[0], size); + if (ioerr || (actual != size)) + return 0; int err; std::vector<uint8_t> gz_ptr(8); @@ -126,7 +127,7 @@ int apd_format::identify(util::random_read &io, uint32_t form_factor, const std: err = inflateEnd(&d_stream); if (err != Z_OK) return 0; - img = gz_ptr; + img = std::move(gz_ptr); } if (!memcmp(&img[0], APD_HEADER, sizeof(APD_HEADER))) { @@ -143,8 +144,9 @@ bool apd_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [ioerr, actual] = read_at(io, 0, &img[0], size); + if (ioerr || (actual != size)) + return false; int err; std::vector<uint8_t> gz_ptr; diff --git a/src/lib/formats/apf_apt.cpp b/src/lib/formats/apf_apt.cpp index dd1d119b010..9930d501652 100644 --- a/src/lib/formats/apf_apt.cpp +++ b/src/lib/formats/apf_apt.cpp @@ -152,12 +152,12 @@ static int apf_cpf_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int apf_apt_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int apf_apt_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return apf_apt_handle_cassette(buffer, bytes); } -static int apf_cpf_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int apf_cpf_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return apf_cpf_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/apridisk.cpp b/src/lib/formats/apridisk.cpp index fafc12d9f3c..36ad6018336 100644 --- a/src/lib/formats/apridisk.cpp +++ b/src/lib/formats/apridisk.cpp @@ -38,8 +38,9 @@ const char *apridisk_format::extensions() const noexcept int apridisk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[APR_HEADER_SIZE]; - size_t actual; - io.read_at(0, header, APR_HEADER_SIZE, actual); + auto const [err, actual] = read_at(io, 0, header, APR_HEADER_SIZE); + if (err || (APR_HEADER_SIZE != actual)) + return 0; const char magic[] = "ACT Apricot disk image\x1a\x04"; @@ -64,11 +65,9 @@ bool apridisk_format::load(util::random_read &io, uint32_t form_factor, const st while (file_offset < file_size) { - size_t actual; - // read sector header uint8_t sector_header[16]; - io.read_at(file_offset, sector_header, 16, actual); + read_at(io, file_offset, sector_header, 16); // FIXME: check for errors and premature EOF uint32_t type = get_u32le(§or_header[0]); uint16_t compression = get_u16le(§or_header[4]); @@ -103,7 +102,7 @@ bool apridisk_format::load(util::random_read &io, uint32_t form_factor, const st case APR_COMPRESSED: { uint8_t comp[3]; - io.read_at(file_offset, comp, 3, actual); + read_at(io, file_offset, comp, 3); // FIXME: check for errors and premature EOF uint16_t length = get_u16le(&comp[0]); if (length != SECTOR_SIZE) @@ -117,7 +116,7 @@ bool apridisk_format::load(util::random_read &io, uint32_t form_factor, const st break; case APR_UNCOMPRESSED: - io.read_at(file_offset, data_ptr, SECTOR_SIZE, actual); + read_at(io, file_offset, data_ptr, SECTOR_SIZE); // FIXME: check for errors and premature EOF break; default: diff --git a/src/lib/formats/as_dsk.cpp b/src/lib/formats/as_dsk.cpp index 5c8a0545870..0fad7217585 100644 --- a/src/lib/formats/as_dsk.cpp +++ b/src/lib/formats/as_dsk.cpp @@ -4,55 +4,17 @@ // Applesauce solved output formats #include "as_dsk.h" + #include "ioprocs.h" +#include "multibyte.h" #include <string.h> -as_format::as_format() : floppy_image_format_t() -{ -} -uint32_t as_format::find_tag(const std::vector<uint8_t> &data, uint32_t tag) -{ - uint32_t offset = 12; - do { - if(r32(data, offset) == tag) - return offset + 8; - offset += r32(data, offset+4) + 8; - } while(offset < data.size() - 8); - return 0; -} +namespace { -uint32_t as_format::r32(const std::vector<uint8_t> &data, uint32_t offset) -{ - return data[offset] | (data[offset+1] << 8) | (data[offset+2] << 16) | (data[offset+3] << 24); -} - -uint16_t as_format::r16(const std::vector<uint8_t> &data, uint32_t offset) -{ - return data[offset] | (data[offset+1] << 8); -} - -void as_format::w32(std::vector<uint8_t> &data, int offset, uint32_t value) -{ - data[offset] = value; - data[offset+1] = value >> 8; - data[offset+2] = value >> 16; - data[offset+3] = value >> 24; -} - -void as_format::w16(std::vector<uint8_t> &data, int offset, uint16_t value) -{ - data[offset] = value; - data[offset+1] = value >> 8; -} - -uint8_t as_format::r8(const std::vector<uint8_t> &data, uint32_t offset) -{ - return data[offset]; -} - -uint32_t as_format::crc32r(const uint8_t *data, uint32_t size) +template <typename T> +uint32_t crc32r(T &&data, uint32_t size) { // Reversed crc32 uint32_t crc = 0xffffffff; @@ -67,15 +29,35 @@ uint32_t as_format::crc32r(const uint8_t *data, uint32_t size) return ~crc; } -bool as_format::load_bitstream_track(const std::vector<uint8_t> &img, floppy_image &image, int head, int track, int subtrack, uint8_t idx, uint32_t off_trks, bool may_be_short, bool set_variant) +template <typename T> +uint32_t find_tag(T &&data, size_t size, uint32_t tag) +{ + uint32_t offset = 12; + do { + if(get_u32le(&data[offset]) == tag) + return offset + 8; + offset += get_u32le(&data[offset+4]) + 8; + } while(offset < (size - 8)); + return 0; +} + +} // anonymous namespace + + +as_format::as_format() : floppy_image_format_t() +{ +} + + +bool as_format::load_bitstream_track(const uint8_t *img, floppy_image &image, int head, int track, int subtrack, uint8_t idx, uint32_t off_trks, bool may_be_short, bool set_variant) { uint32_t trks_off = off_trks + (idx * 8); - uint32_t track_size = r32(img, trks_off + 4); + uint32_t track_size = get_u32le(&img[trks_off + 4]); if (track_size == 0) return false; - uint32_t boff = (uint32_t)r16(img, trks_off + 0) * 512; + uint32_t boff = (uint32_t)get_u16le(&img[trks_off + 0]) * 512; // With 5.25 floppies the end-of-track may be missing // if unformatted. Accept track length down to 95% of @@ -92,15 +74,15 @@ bool as_format::load_bitstream_track(const std::vector<uint8_t> &img, floppy_ima generate_track_from_bitstream(track, head, &img[boff], track_size, image, subtrack, 0xffff); if(set_variant) - image.set_variant(r32(img, trks_off + 4) >= 90000 ? floppy_image::DSHD : floppy_image::DSDD); + image.set_variant(get_u32le(&img[trks_off + 4]) >= 90000 ? floppy_image::DSHD : floppy_image::DSDD); return true; } -void as_format::load_flux_track(const std::vector<uint8_t> &img, floppy_image &image, int head, int track, int subtrack, uint8_t fidx, uint32_t off_trks) +void as_format::load_flux_track(const uint8_t *img, floppy_image &image, int head, int track, int subtrack, uint8_t fidx, uint32_t off_trks) { uint32_t trks_off = off_trks + (fidx * 8); - uint32_t boff = (uint32_t)r16(img, trks_off + 0) * 512; - uint32_t track_size = r32(img, trks_off + 4); + uint32_t boff = (uint32_t)get_u16le(&img[trks_off + 0]) * 512; + uint32_t track_size = get_u32le(&img[trks_off + 4]); uint32_t total_ticks = 0; for(uint32_t i=0; i != track_size; i++) @@ -239,13 +221,13 @@ bool as_format::test_flux(const std::vector<tdata> &tracks) void as_format::save_tracks(std::vector<uint8_t> &data, const std::vector<tdata> &tracks, uint32_t total_blocks, bool has_flux) { - w32(data, 80, 0x50414D54); // TMAP - w32(data, 84, 160); // size + put_u32le(&data[80], 0x50414d54); // TMAP + put_u32le(&data[84], 160); // size uint32_t fstart = 1536 + total_blocks*512; if(has_flux) { - w32(data, fstart, 0x58554c46); - w32(data, fstart+4, 160); + put_u32le(&data[fstart], 0x58554c46); + put_u32le(&data[fstart+4], 160); fstart += 8; } @@ -264,8 +246,8 @@ void as_format::save_tracks(std::vector<uint8_t> &data, const std::vector<tdata> } } - w32(data, 248, 0x534B5254); // TRKS - w32(data, 252, 1280 + total_blocks*512); // size + put_u32le(&data[248], 0x534b5254); // TRKS + put_u32le(&data[252], 1280 + total_blocks*512); // size uint8_t tid = 0; uint16_t tb = 3; @@ -274,14 +256,14 @@ void as_format::save_tracks(std::vector<uint8_t> &data, const std::vector<tdata> int size = tracks[i].data.size(); int blocks = (size + 511) / 512; memcpy(data.data() + tb*512, tracks[i].data.data(), size); - w16(data, 256 + tid*8, tb); - w16(data, 256 + tid*8 + 2, blocks); - w32(data, 256 + tid*8 + 4, tracks[i].track_size); + put_u16le(&data[256 + tid*8], tb); + put_u16le(&data[256 + tid*8 + 2], blocks); + put_u32le(&data[256 + tid*8 + 4], tracks[i].track_size); tb += blocks; tid ++; } - w32(data, 8, crc32r(&data[12], data.size() - 12)); + put_u32le(&data[8], crc32r(&data[12], data.size() - 12)); } @@ -316,10 +298,10 @@ const uint8_t woz_format::signature2[8] = { 0x57, 0x4f, 0x5a, 0x32, 0xff, 0x0a, int woz_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[8]; - size_t actual; - io.read_at(0, header, 8, actual); - if (!memcmp(header, signature, 8)) return FIFID_SIGN; - if (!memcmp(header, signature2, 8)) return FIFID_SIGN; + auto const [err, actual] = read_at(io, 0, header, 8); + if(err || (8 != actual)) return 0; + if(!memcmp(header, signature, 8)) return FIFID_SIGN; + if(!memcmp(header, signature2, 8)) return FIFID_SIGN; return 0; } @@ -328,9 +310,9 @@ bool woz_format::load(util::random_read &io, uint32_t form_factor, const std::ve 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); + auto const [err, img, actual] = read_at(io, 0, image_size); + if(err || (actual != image_size)) + return false; // Check signature if((memcmp(&img[0], signature, 8)) && (memcmp(&img[0], signature2, 8))) @@ -340,29 +322,29 @@ bool woz_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(!memcmp(&img[0], signature2, 8)) woz_vers = 2; // Check integrity - uint32_t crc = crc32r(&img[12], img.size() - 12); - if(crc != r32(img, 8)) + uint32_t crc = crc32r(&img[12], image_size - 12); + if(crc != get_u32le(&img[8])) return false; - uint32_t off_info = find_tag(img, 0x4f464e49); - uint32_t off_tmap = find_tag(img, 0x50414d54); - uint32_t off_trks = find_tag(img, 0x534b5254); -// uint32_t off_writ = find_tag(img, 0x54495257); + uint32_t off_info = find_tag(img, image_size, 0x4f464e49); + uint32_t off_tmap = find_tag(img, image_size, 0x50414d54); + uint32_t off_trks = find_tag(img, image_size, 0x534b5254); +// uint32_t off_writ = find_tag(img, image_size, 0x54495257); if(!off_info || !off_tmap || !off_trks) return false; - uint32_t info_vers = r8(img, off_info + 0); + uint32_t info_vers = img[off_info + 0]; if(info_vers < 1 || info_vers > 3) return false; - uint16_t off_flux = info_vers < 3 ? 0 : r16(img, off_info + 46); - uint16_t flux_size = info_vers < 3 ? 0 : r16(img, off_info + 48); + uint16_t off_flux = (info_vers < 3) ? 0 : get_u16le(&img[off_info + 46]); + uint16_t flux_size = (info_vers < 3) ? 0 : get_u16le(&img[off_info + 48]); if(!flux_size) off_flux = 0; - bool is_35 = r8(img, off_info + 1) == 2; + bool is_35 = img[off_info + 1] == 2; if((form_factor == floppy_image::FF_35 && !is_35) || (form_factor == floppy_image::FF_525 && is_35)) return false; @@ -374,36 +356,36 @@ bool woz_format::load(util::random_read &io, uint32_t form_factor, const std::ve else image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); - if (woz_vers == 1) { + if(woz_vers == 1) { for (unsigned int trkid = 0; trkid != limit; trkid++) { int head = is_35 && trkid >= 80 ? 1 : 0; int track = is_35 ? trkid % 80 : trkid / 4; int subtrack = is_35 ? 0 : trkid & 3; - uint8_t idx = r8(img, off_tmap + trkid); + uint8_t idx = img[off_tmap + trkid]; if(idx != 0xff) { uint32_t boff = off_trks + 6656*idx; - if (r16(img, boff + 6648) == 0) + if (get_u16le(&img[boff + 6648]) == 0) return false; - generate_track_from_bitstream(track, head, &img[boff], r16(img, boff + 6648), image, subtrack, r16(img, boff + 6650)); + generate_track_from_bitstream(track, head, &img[boff], get_u16le(&img[boff + 6648]), image, subtrack, get_u16le(&img[boff + 6650])); if(is_35 && !track && head) image.set_variant(floppy_image::DSDD); } } - } else if (woz_vers == 2) { + } else if(woz_vers == 2) { for (unsigned int trkid = 0; trkid != limit; trkid++) { int head = is_35 && trkid & 1 ? 1 : 0; int track = is_35 ? trkid >> 1 : trkid / 4; int subtrack = is_35 ? 0 : trkid & 3; - uint8_t idx = r8(img, off_tmap + trkid); - uint8_t fidx = off_flux ? r8(img, off_flux*512 + 8 + trkid) : 0xff; + uint8_t idx = img[off_tmap + trkid]; + uint8_t fidx = off_flux ? img[off_flux*512 + 8 + trkid] : 0xff; - if(fidx != 0xff) - load_flux_track(img, image, head, track, subtrack, fidx, off_trks); + if(fidx != 0xff) { + load_flux_track(&img[0], image, head, track, subtrack, fidx, off_trks); - else if(idx != 0xff) { - if(!load_bitstream_track(img, image, head, track, subtrack, idx, off_trks, !is_35, is_35 && !track && head)) + } else if(idx != 0xff) { + if(!load_bitstream_track(&img[0], image, head, track, subtrack, idx, off_trks, !is_35, is_35 && !track && head)) return false; } } @@ -445,31 +427,30 @@ bool woz_format::save(util::random_read_write &io, const std::vector<uint32_t> & memcpy(&data[0], signature2, 8); - w32(data, 12, 0x4F464E49); // INFO - w32(data, 16, 60); // size - data[20] = 3; // chunk version + put_u32le(&data[12], 0x4f464e49); // INFO + put_u32le(&data[16], 60); // size + data[20] = 3; // chunk version data[21] = image.get_form_factor() == floppy_image::FF_525 ? 1 : 2; - data[22] = 0; // not write protected - data[23] = 1; // synchronized, since our internal format is - data[24] = 1; // weak bits are generated, not stored + data[22] = 0; // not write protected + data[23] = 1; // synchronized, since our internal format is + data[24] = 1; // weak bits are generated, not stored data[25] = 'M'; data[26] = 'A'; data[27] = 'M'; data[28] = 'E'; memset(&data[29], ' ', 32-4); data[57] = twosided ? 2 : 1; - data[58] = 0; // boot sector unknown + data[58] = 0; // boot sector unknown data[59] = image.get_form_factor() == floppy_image::FF_525 ? 32 : image.get_variant() == floppy_image::DSHD ? 8 : 16; - w16(data, 60, 0); // compatibility unknown - w16(data, 62, 0); // needed ram unknown - w16(data, 64, max_blocks); - w16(data, 66, has_flux ? total_blocks+3 : 0); - w16(data, 68, max_blocks); + put_u16le(&data[60], 0); // compatibility unknown + put_u16le(&data[62], 0); // needed RAM unknown + put_u16le(&data[64], max_blocks); + put_u16le(&data[66], has_flux ? total_blocks+3 : 0); + put_u16le(&data[68], max_blocks); save_tracks(data, tracks, total_blocks, has_flux); - size_t actual; - io.write_at(0, data.data(), data.size(), actual); + /*auto const [err, actual] =*/ write_at(io, 0, data.data(), data.size()); // FIXME: check for errors return true; } @@ -505,9 +486,9 @@ const uint8_t moof_format::signature[8] = { 0x4d, 0x4f, 0x4f, 0x46, 0xff, 0x0a, int moof_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[8]; - size_t actual; - io.read_at(0, header, 8, actual); - if (!memcmp(header, signature, 8)) return FIFID_SIGN; + auto const [err, actual] = read_at(io, 0, header, 8); + if(err || (8 != actual)) return 0; + if(!memcmp(header, signature, 8)) return FIFID_SIGN; return 0; } @@ -516,37 +497,37 @@ bool moof_format::load(util::random_read &io, uint32_t form_factor, const std::v 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); + auto const [err, img, actual] = read_at(io, 0, image_size); + if(err || (actual != image_size)) + return false; // Check signature if(memcmp(&img[0], signature, 8)) return false; // Check integrity - uint32_t crc = crc32r(&img[12], img.size() - 12); - if(crc != r32(img, 8)) + uint32_t crc = crc32r(&img[12], image_size - 12); + if(crc != get_u32le(&img[8])) return false; - uint32_t off_info = find_tag(img, 0x4f464e49); - uint32_t off_tmap = find_tag(img, 0x50414d54); - uint32_t off_trks = find_tag(img, 0x534b5254); + uint32_t off_info = find_tag(img, image_size, 0x4f464e49); + uint32_t off_tmap = find_tag(img, image_size, 0x50414d54); + uint32_t off_trks = find_tag(img, image_size, 0x534b5254); if(!off_info || !off_tmap || !off_trks) return false; - uint32_t info_vers = r8(img, off_info + 0); + uint32_t info_vers = img[off_info + 0]; if(info_vers != 1) return false; - uint16_t off_flux = r16(img, off_info + 40); - uint16_t flux_size = r16(img, off_info + 42); + uint16_t off_flux = get_u16le(&img[off_info + 40]); + uint16_t flux_size = get_u16le(&img[off_info + 42]); if(!flux_size) off_flux = 0; - switch(r8(img, off_info + 1)) { + switch(img[off_info + 1]) { case 1: image.set_form_variant(floppy_image::FF_35, floppy_image::SSDD); break; @@ -564,14 +545,14 @@ bool moof_format::load(util::random_read &io, uint32_t form_factor, const std::v int head = trkid & 1; int track = trkid >> 1; - uint8_t idx = r8(img, off_tmap + trkid); - uint8_t fidx = off_flux ? r8(img, off_flux*512 + 8 + trkid) : 0xff; + uint8_t idx = img[off_tmap + trkid]; + uint8_t fidx = off_flux ? img[off_flux*512 + 8 + trkid] : 0xff; - if(fidx != 0xff) - load_flux_track(img, image, head, track, 0, fidx, off_trks); + if(fidx != 0xff) { + load_flux_track(&img[0], image, head, track, 0, fidx, off_trks); - else if(idx != 0xff) { - if(!load_bitstream_track(img, image, head, track, 0, idx, off_trks, false, false)) + } else if(idx != 0xff) { + if(!load_bitstream_track(&img[0], image, head, track, 0, idx, off_trks, false, false)) return false; } } @@ -606,27 +587,26 @@ bool moof_format::save(util::random_read_write &io, const std::vector<uint32_t> memcpy(&data[0], signature, 8); - w32(data, 12, 0x4F464E49); // INFO - w32(data, 16, 60); // size - data[20] = 1; // chunk version + put_u32le(&data[12], 0x4f464e49); // INFO + put_u32le(&data[16], 60); // size + data[20] = 1; // chunk version data[21] = is_hd ? 3 : twosided ? 2 : 1; // variant - data[22] = 0; // not write protected - data[23] = 1; // synchronized, since our internal format is - data[24] = is_hd ? 8 : 16; // optimal timing + data[22] = 0; // not write protected + data[23] = 1; // synchronized, since our internal format is + data[24] = is_hd ? 8 : 16; // optimal timing data[25] = 'M'; data[26] = 'A'; data[27] = 'M'; data[28] = 'E'; memset(&data[29], ' ', 32-4); - data[57] = 0; // pad - w16(data, 58, max_blocks); - w16(data, 60, has_flux ? total_blocks+3 : 0); - w16(data, 62, max_blocks); + data[57] = 0; // pad + put_u16le(&data[58], max_blocks); + put_u16le(&data[60], has_flux ? total_blocks+3 : 0); + put_u16le(&data[62], max_blocks); save_tracks(data, tracks, total_blocks, has_flux); - size_t actual; - io.write_at(0, data.data(), data.size(), actual); + /*auto const [err, actual] =*/ write_at(io, 0, data.data(), data.size()); // FIXME: check for errors return true; } diff --git a/src/lib/formats/as_dsk.h b/src/lib/formats/as_dsk.h index ec0a785d151..8871bc1ed11 100644 --- a/src/lib/formats/as_dsk.h +++ b/src/lib/formats/as_dsk.h @@ -23,16 +23,8 @@ protected: bool flux = false; }; - static uint32_t r32(const std::vector<uint8_t> &data, uint32_t offset); - static uint16_t r16(const std::vector<uint8_t> &data, uint32_t offset); - static uint8_t r8(const std::vector<uint8_t> &data, uint32_t offset); - static void w32(std::vector<uint8_t> &data, int offset, uint32_t value); - static void w16(std::vector<uint8_t> &data, int offset, uint16_t value); - static uint32_t crc32r(const uint8_t *data, uint32_t size); - static uint32_t find_tag(const std::vector<uint8_t> &data, uint32_t tag); - - static bool load_bitstream_track(const std::vector<uint8_t> &img, floppy_image &image, int head, int track, int subtrack, uint8_t idx, uint32_t off_trks, bool may_be_short, bool set_variant); - static void load_flux_track(const std::vector<uint8_t> &img, floppy_image &image, int head, int track, int subtrack, uint8_t fidx, uint32_t off_trks); + static bool load_bitstream_track(const uint8_t *img, floppy_image &image, int head, int track, int subtrack, uint8_t idx, uint32_t off_trks, bool may_be_short, bool set_variant); + static void load_flux_track(const uint8_t *img, floppy_image &image, int head, int track, int subtrack, uint8_t fidx, uint32_t off_trks); static tdata analyze_for_save(const floppy_image &image, int head, int track, int subtrack, int speed_zone); static std::pair<int, int> count_blocks(const std::vector<tdata> &tracks); diff --git a/src/lib/formats/bk0010_dsk.cpp b/src/lib/formats/bk0010_dsk.cpp new file mode 100644 index 00000000000..8922b144fcd --- /dev/null +++ b/src/lib/formats/bk0010_dsk.cpp @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + formats/bk0010_dsk.cpp + + Floppies used by BK (BY: device), DVK (MY: device) and UKNC + (MZ: device) + +*********************************************************************/ + +#include "formats/bk0010_dsk.h" + +bk0010_format::bk0010_format() : wd177x_format(formats) +{ +} + +// gap sizes taken from BKBTL emulator +const bk0010_format::format bk0010_format::formats[] = { + { + floppy_image::FF_525, floppy_image::SSQD, floppy_image::MFM, + 2000, // 2us, 300rpm + 10, 80, 1, + 512, {}, + 1, {}, + 42, 22, 36 + }, + { + floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM, + 2000, // 2us, 300rpm + 10, 80, 2, + 512, {}, + 1, {}, + 42, 22, 36 + }, + {} +}; + +const bk0010_format FLOPPY_BK0010_FORMAT; diff --git a/src/lib/formats/bk0010_dsk.h b/src/lib/formats/bk0010_dsk.h new file mode 100644 index 00000000000..96b00ebede7 --- /dev/null +++ b/src/lib/formats/bk0010_dsk.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + formats/bk0010_dsk.h + +*********************************************************************/ +#ifndef MAME_FORMATS_BK0010_DSK_H +#define MAME_FORMATS_BK0010_DSK_H + +#pragma once + +#include "wd177x_dsk.h" + +class bk0010_format : public wd177x_format +{ +public: + bk0010_format(); + + virtual const char *name() const noexcept override { return "bk0010"; } + virtual const char *description() const noexcept override { return "BK-0010 disk image"; } + virtual const char *extensions() const noexcept override { return "img,bkd"; } + +private: + static const format formats[]; +}; + +extern const bk0010_format FLOPPY_BK0010_FORMAT; + +#endif // MAME_FORMATS_BK0010_DSK_H diff --git a/src/lib/formats/camplynx_cas.cpp b/src/lib/formats/camplynx_cas.cpp index a6151462911..545814b954f 100644 --- a/src/lib/formats/camplynx_cas.cpp +++ b/src/lib/formats/camplynx_cas.cpp @@ -179,7 +179,7 @@ static int camplynx_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int camplynx_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int camplynx_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return camplynx_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/cassimg.cpp b/src/lib/formats/cassimg.cpp index 38be38db9b1..cea484f2735 100644 --- a/src/lib/formats/cassimg.cpp +++ b/src/lib/formats/cassimg.cpp @@ -366,8 +366,7 @@ void cassette_image::change(util::random_read_write::ptr &&io, const Format *for void cassette_image::image_read(void *buffer, uint64_t offset, size_t length) { - size_t actual; - m_io->read_at(offset, buffer, length, actual); + /*auto const [err, actual] =*/ read_at(*m_io, offset, buffer, length); // FIXME: check for errors and premature EOF } @@ -383,8 +382,7 @@ uint8_t cassette_image::image_read_byte(uint64_t offset) void cassette_image::image_write(const void *buffer, uint64_t offset, size_t length) { - size_t actual; - m_io->write_at(offset, buffer, length, actual); + /*auto const [err, actual] =*/ write_at(*m_io, offset, buffer, length); // FIXME: check for errors } @@ -793,8 +791,8 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l error err; int length; int sample_count; - std::vector<uint8_t> bytes; - std::vector<int16_t> samples; + std::unique_ptr<int16_t []> samples; + std::unique_ptr<uint8_t []> chunk; int pos = 0; uint64_t offset = 0; @@ -803,7 +801,7 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l assert(legacy_args->trailer_samples >= 0); assert(legacy_args->fill_wave); - uint64_t size = image_size(); + const uint64_t size = image_size(); /* normalize the args */ LegacyWaveFiller args = *legacy_args; @@ -814,21 +812,24 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l if (args.sample_frequency == 0) args.sample_frequency = 11025; - /* allocate a buffer for the binary data */ - std::vector<uint8_t> chunk(args.chunk_size); - /* determine number of samples */ if (args.chunk_sample_calc != nullptr) { - if (size > 0x7FFFFFFF) + if (size > 0x7fffffff) + { + err = error::OUT_OF_MEMORY; + goto done; + } + + std::unique_ptr<uint8_t []> bytes(new (std::nothrow) uint8_t [size]); + if (!bytes) { err = error::OUT_OF_MEMORY; goto done; } - bytes.resize(size); - image_read(&bytes[0], 0, size); - sample_count = args.chunk_sample_calc(&bytes[0], (int)size); + image_read(bytes.get(), 0, size); + sample_count = args.chunk_sample_calc(bytes.get(), (int)size); // chunk_sample_calc functions report errors by returning negative numbers if (sample_count < 0) @@ -848,12 +849,17 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l sample_count += args.header_samples + args.trailer_samples; /* allocate a buffer for the completed samples */ - samples.resize(sample_count); + samples.reset(new (std::nothrow) int16_t [sample_count]); + if (!samples) + { + err = error::OUT_OF_MEMORY; + goto done; + } /* if there has to be a header */ if (args.header_samples > 0) { - length = args.fill_wave(&samples[pos], sample_count - pos, CODE_HEADER); + length = args.fill_wave(&samples[pos], sample_count - pos, CODE_HEADER, -1); if (length < 0) { err = error::INVALID_IMAGE; @@ -863,12 +869,19 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l } /* convert the file data to samples */ + chunk.reset(new (std::nothrow) uint8_t [args.chunk_size]); + if (!chunk) + { + err = error::OUT_OF_MEMORY; + goto done; + } while ((pos < sample_count) && (offset < size)) { - image_read(&chunk[0], offset, args.chunk_size); - offset += args.chunk_size; + const int slice = std::min<int>(args.chunk_size, size - offset); + image_read(chunk.get(), offset, slice); + offset += slice; - length = args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]); + length = args.fill_wave(&samples[pos], sample_count - pos, chunk.get(), slice); if (length < 0) { err = error::INVALID_IMAGE; @@ -878,11 +891,12 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l if (length == 0) break; } + chunk.reset(); /* if there has to be a trailer */ if (args.trailer_samples > 0) { - length = args.fill_wave(&samples[pos], sample_count - pos, CODE_TRAILER); + length = args.fill_wave(&samples[pos], sample_count - pos, CODE_TRAILER, -1); if (length < 0) { err = error::INVALID_IMAGE; diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h index 9714e8e223b..9867ecbdf4a 100644 --- a/src/lib/formats/cassimg.h +++ b/src/lib/formats/cassimg.h @@ -120,7 +120,7 @@ public: /* code to adapt existing legacy fill_wave functions */ struct LegacyWaveFiller { - int (*fill_wave)(int16_t *, int, uint8_t *) = nullptr; + int (*fill_wave)(int16_t *, int, const uint8_t *, int) = nullptr; int chunk_size = 0; int chunk_samples = 0; int (*chunk_sample_calc)(const uint8_t *bytes, int length) = nullptr; diff --git a/src/lib/formats/cbm_crt.cpp b/src/lib/formats/cbm_crt.cpp index b088507208f..6bc9e0f8d23 100644 --- a/src/lib/formats/cbm_crt.cpp +++ b/src/lib/formats/cbm_crt.cpp @@ -46,6 +46,8 @@ #include "osdcore.h" // osd_printf_* +#include <tuple> + //************************************************************************** // MACROS/CONSTANTS @@ -137,8 +139,7 @@ std::string cbm_crt_get_card(util::core_file &file) { // read the header cbm_crt_header header; - size_t actual; - std::error_condition err = file.read(&header, CRT_HEADER_LENGTH, actual); + auto const [err, actual] = read(file, &header, CRT_HEADER_LENGTH); if (!err && (CRT_HEADER_LENGTH == actual) && !memcmp(header.signature, CRT_SIGNATURE, 16)) { @@ -157,11 +158,13 @@ std::string cbm_crt_get_card(util::core_file &file) bool cbm_crt_read_header(util::core_file &file, size_t *roml_size, size_t *romh_size, int *exrom, int *game) { + std::error_condition err; size_t actual; // read the header cbm_crt_header header; - if (file.read(&header, CRT_HEADER_LENGTH, actual)) + std::tie(err, actual) = read(file, &header, CRT_HEADER_LENGTH); + if (err) return false; if ((CRT_HEADER_LENGTH != actual) || (memcmp(header.signature, CRT_SIGNATURE, 16) != 0)) @@ -184,7 +187,8 @@ bool cbm_crt_read_header(util::core_file &file, size_t *roml_size, size_t *romh_ while (!file.eof()) { cbm_crt_chip chip; - if (file.read(&chip, CRT_CHIP_LENGTH, actual) || (CRT_CHIP_LENGTH != actual)) + std::tie(err, actual) = read(file, &chip, CRT_CHIP_LENGTH); + if (err || (CRT_CHIP_LENGTH != actual)) return false; const uint16_t address = get_u16be(chip.start_address); @@ -228,21 +232,22 @@ bool cbm_crt_read_data(util::core_file &file, uint8_t *roml, uint8_t *romh) while (!file.eof()) { + std::error_condition err; size_t actual; cbm_crt_chip chip; - if (file.read(&chip, CRT_CHIP_LENGTH, actual) || (CRT_CHIP_LENGTH != actual)) + std::tie(err, actual) = read(file, &chip, CRT_CHIP_LENGTH); + if (err || (CRT_CHIP_LENGTH != actual)) return false; const uint16_t address = get_u16be(chip.start_address); const uint16_t size = get_u16be(chip.image_size); - std::error_condition err; switch (address) { - case 0x8000: err = file.read(roml + roml_offset, size, actual); roml_offset += size; break; - case 0xa000: err = file.read(romh + romh_offset, size, actual); romh_offset += size; break; - case 0xe000: err = file.read(romh + romh_offset, size, actual); romh_offset += size; break; + case 0x8000: std::tie(err, actual) = read(file, roml + roml_offset, size); roml_offset += size; break; + case 0xa000: std::tie(err, actual) = read(file, romh + romh_offset, size); romh_offset += size; break; + case 0xe000: std::tie(err, actual) = read(file, romh + romh_offset, size); romh_offset += size; break; // FIXME: surely one needs to report an error or skip over the data if the load address is not recognised? } if (err) // TODO: check size - all bets are off if the address isn't recognised anyway diff --git a/src/lib/formats/cbm_tap.cpp b/src/lib/formats/cbm_tap.cpp index 743ad4282d2..65c265ac86f 100644 --- a/src/lib/formats/cbm_tap.cpp +++ b/src/lib/formats/cbm_tap.cpp @@ -330,7 +330,7 @@ static int cbm_tap_to_wav_size( const uint8_t *tapdata, int taplen ) return size; } -static int cbm_tap_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) +static int cbm_tap_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int16_t *p = buffer; diff --git a/src/lib/formats/ccvf_dsk.cpp b/src/lib/formats/ccvf_dsk.cpp index 829be2a0019..d2c8da8e083 100644 --- a/src/lib/formats/ccvf_dsk.cpp +++ b/src/lib/formats/ccvf_dsk.cpp @@ -50,8 +50,10 @@ const ccvf_format::format ccvf_format::file_formats[] = { int ccvf_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { char h[36]; - size_t actual; - io.read_at(0, h, 36, actual); + auto const [err, actual] = read_at(io, 0, h, 36); + if (err || (36 != actual)) + return 0; + if (!memcmp(h, "Compucolor Virtual Floppy Disk Image", 36)) return FIFID_SIGN; @@ -96,9 +98,9 @@ bool ccvf_format::load(util::random_read &io, uint32_t form_factor, const std::v if (io.length(size)) return false; - std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto [err, img, actual] = read_at(io, 0, size); + if (err || (actual != size)) + return false; std::string ccvf = std::string((const char *)&img[0], size); std::vector<uint8_t> bytes(78720); diff --git a/src/lib/formats/cgen_cas.cpp b/src/lib/formats/cgen_cas.cpp index c0737db635b..1ae1682cba9 100644 --- a/src/lib/formats/cgen_cas.cpp +++ b/src/lib/formats/cgen_cas.cpp @@ -108,7 +108,7 @@ static int cgenie_handle_cas(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int cgenie_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int cgenie_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return cgenie_handle_cas(buffer, bytes); } diff --git a/src/lib/formats/concept_dsk.cpp b/src/lib/formats/concept_dsk.cpp index e026090e19f..52950b3e57d 100644 --- a/src/lib/formats/concept_dsk.cpp +++ b/src/lib/formats/concept_dsk.cpp @@ -114,8 +114,7 @@ bool cc525dsdd_format::load(util::random_read &io, uint32_t form_factor, const s int track_size = sector_count*512; 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); + /*auto const [err, acutal] =*/ read_at(io, (track*head_count + head) * track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(cc_9_desc, track, head, sectors, sector_count, 100000, image); } } @@ -146,8 +145,7 @@ bool cc525dsdd_format::save(util::random_read_write &io, const std::vector<uint3 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); - size_t actual; - io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors } } diff --git a/src/lib/formats/coupedsk.cpp b/src/lib/formats/coupedsk.cpp index 6e43aa9c301..a3edc5c7b40 100644 --- a/src/lib/formats/coupedsk.cpp +++ b/src/lib/formats/coupedsk.cpp @@ -94,8 +94,7 @@ bool mgt_format::load(util::random_read &io, uint32_t form_factor, const std::ve int track_size = sector_count*512; for(int head=0; head < 2; head++) { for(int track=0; track < 80; track++) { - size_t actual; - io.read_at((track*2+head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ read_at(io, (track*2+head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(desc_10, track, head, sectors, sector_count+1, 100000, image); } } @@ -120,8 +119,7 @@ bool mgt_format::save(util::random_read_write &io, const std::vector<uint32_t> & 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); - size_t actual; - io.write_at((track*2+head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*2+head)*track_size, sectdata, track_size); // FIXME: check for errors } } diff --git a/src/lib/formats/cp68_dsk.cpp b/src/lib/formats/cp68_dsk.cpp index c6eb005f1c0..5872da350b6 100644 --- a/src/lib/formats/cp68_dsk.cpp +++ b/src/lib/formats/cp68_dsk.cpp @@ -51,6 +51,9 @@ #include "ioprocs.h" +#include <tuple> + + namespace { class cp68_formats : public wd177x_format @@ -115,8 +118,8 @@ int cp68_format::find_size(util::random_read &io, uint32_t form_factor, const st std::error_condition ec; // Look at the boot sector. - ec = io.read_at(128 * 0, &boot0, sizeof(boot0), actual); - if (ec || actual == 0) + std::tie(ec, actual) = read_at(io, 128 * 0, &boot0, sizeof(boot0)); + if (ec || actual == 0) // FIXME: what's the actual minimum size boot sector to probe? return -1; uint8_t boot0_sector_id = 1; // uint8_t boot1_sector_id = 2; @@ -125,8 +128,7 @@ int cp68_format::find_size(util::random_read &io, uint32_t form_factor, const st // set the numbering of the first two sectors. If this is shown to not // be practical in some common cases then a separate format variant // might be needed. - if (boot0[0] == 0xbd && boot0[3] == 0x86) - { + if (boot0[0] == 0xbd && boot0[3] == 0x86) { // Found a 6800 jsr and ldaa, looks like a CP68 6800 boot sector. boot0_sector_id = 0; } @@ -135,8 +137,8 @@ int cp68_format::find_size(util::random_read &io, uint32_t form_factor, const st const format &f = cp68_formats::formats[i]; // Look at the system information sector. - ec = io.read_at(f.sector_base_size * 2, &info, sizeof(struct cp68_formats::sysinfo_sector_cp68), actual); - if (ec || actual == 0) + std::tie(ec, actual) = read_at(io, f.sector_base_size * 2, &info, sizeof(struct cp68_formats::sysinfo_sector_cp68)); + if (ec || actual == 0) // FIXME: what's the actual minimum sector size? continue; LOG_FORMATS("CP68 floppy dsk: size %d bytes, %d total sectors, %d remaining bytes, expected form factor %x\n", (uint32_t)size, (uint32_t)size / f.sector_base_size, (uint32_t)size % f.sector_base_size, form_factor); diff --git a/src/lib/formats/cqm_dsk.cpp b/src/lib/formats/cqm_dsk.cpp index 47fa0fddfbe..850d223da7a 100644 --- a/src/lib/formats/cqm_dsk.cpp +++ b/src/lib/formats/cqm_dsk.cpp @@ -258,8 +258,9 @@ const char *cqm_format::extensions() const noexcept int cqm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[3]; - size_t actual; - io.read_at(0, h, 3, actual); + auto const [err, actual] = read_at(io, 0, h, 3); + if (err || (3 != actual)) + return 0; if (h[0] == 'C' && h[1] == 'Q' && h[2] == 0x14) return FIFID_SIGN; @@ -269,11 +270,10 @@ int cqm_format::identify(util::random_read &io, uint32_t form_factor, const std: bool cqm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - 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.read_at(0, header, CQM_HEADER_SIZE, actual); + read_at(io, 0, header, CQM_HEADER_SIZE); // FIXME: check for errors and premature EOF int sector_size = get_u16le(&header[0x03]); int sector_per_track = get_u16le(&header[0x10]); @@ -317,8 +317,9 @@ bool cqm_format::load(util::random_read &io, uint32_t form_factor, const std::ve uint64_t cqm_size; if (io.length(cqm_size)) return false; - std::vector<uint8_t> cqmbuf(cqm_size); - io.read_at(0, &cqmbuf[0], cqm_size, actual); + auto const [err, cqmbuf, actual] = read_at(io, 0, cqm_size); + if (err || (actual != cqm_size)) + return false; // decode the RLE data for (int s = 0, pos = CQM_HEADER_SIZE + comment_size; pos < cqm_size; ) diff --git a/src/lib/formats/d64_dsk.cpp b/src/lib/formats/d64_dsk.cpp index 56fec80c8c9..e1fb024e74d 100644 --- a/src/lib/formats/d64_dsk.cpp +++ b/src/lib/formats/d64_dsk.cpp @@ -127,8 +127,7 @@ int d64_format::get_disk_id_offset(const format &f) const void d64_format::get_disk_id(const format &f, util::random_read &io, uint8_t &id1, uint8_t &id2) const { uint8_t id[2]; - size_t actual; - io.read_at(get_disk_id_offset(f), id, 2, actual); + /*auto const [err, actual] =*/ read_at(io, get_disk_id_offset(f), id, 2); // FIXME: check for errors and premature EOF id1 = id[0]; id2 = id[1]; } @@ -238,8 +237,7 @@ bool d64_format::load(util::random_read &io, uint32_t form_factor, const std::ve img.resize(size); } - size_t actual; - io.read_at(0, &img[0], size, actual); + /*auto const [err, actual] =*/ read_at(io, 0, &img[0], size); // FIXME: check for errors and premature EOF int track_offset = 0, error_offset = f.sector_count*f.sector_base_size; @@ -294,8 +292,7 @@ bool d64_format::save(util::random_read_write &io, const std::vector<uint32_t> & build_sector_description(f, sectdata, 0, 0, sectors, sector_count); extract_sectors(image, f, sectors, track, head, sector_count); - size_t actual; - io.write_at(offset, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, offset, sectdata, track_size); // FIXME: check for errors } } diff --git a/src/lib/formats/d88_dsk.cpp b/src/lib/formats/d88_dsk.cpp index e0482dadbf3..93a995a47fb 100644 --- a/src/lib/formats/d88_dsk.cpp +++ b/src/lib/formats/d88_dsk.cpp @@ -35,6 +35,8 @@ #include "ioprocs.h" #include "multibyte.h" +#include <tuple> + #define D88_HEADER_LEN 0x2b0 @@ -411,9 +413,11 @@ int d88_format::identify(util::random_read &io, uint32_t form_factor, const std: return 0; uint8_t h[32]; - size_t actual; - io.read_at(0, h, 32, actual); - if((little_endianize_int32(*(uint32_t *)(h+0x1c)) == size) && + auto const [err, actual] = read_at(io, 0, h, 32); + if(err || (32 != actual)) + return 0; + + if(((get_u32le(h+0x1c) == size) || (get_u32le(h+0x1c) == (size >> 1))) && (h[0x1b] == 0x00 || h[0x1b] == 0x10 || h[0x1b] == 0x20 || h[0x1b] == 0x30 || h[0x1b] == 0x40)) return FIFID_SIZE|FIFID_STRUCT; @@ -422,10 +426,13 @@ int d88_format::identify(util::random_read &io, uint32_t form_factor, const std: bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; uint8_t h[32]; - io.read_at(0, h, 32, actual); + std::tie(err, actual) = read_at(io, 0, h, 32); + if(err || (32 != actual)) + return false; int cell_count = 0; int track_count = 0; @@ -470,8 +477,16 @@ bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(!head_count) return false; + int img_tracks, img_heads; + image.get_maximal_geometry(img_tracks, img_heads); + if (track_count > img_tracks) + osd_printf_warning("d88: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", track_count, img_tracks); + + if (head_count > img_heads) + osd_printf_warning("d88: Floppy disk has excess of heads for this drive that will be discarded (floppy heads=%d, drive heads=%d).\n", head_count, img_heads); + uint32_t track_pos[164]; - io.read_at(32, track_pos, 164*4, actual); + std::tie(err, actual) = read_at(io, 32, track_pos, 164*4); // FIXME: check for errors and premature EOF uint64_t file_size; if(io.length(file_size)) @@ -493,7 +508,7 @@ bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::ve return true; uint8_t hs[16]; - io.read_at(pos, hs, 16, actual); + std::tie(err, actual) = read_at(io, pos, hs, 16); // FIXME: check for errors and premature EOF pos += 16; uint16_t size = little_endianize_int16(*(uint16_t *)(hs+14)); @@ -520,7 +535,7 @@ bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(size) { sects[i].data = sect_data + sdatapos; - io.read_at(pos, sects[i].data, size, actual); + std::tie(err, actual) = read_at(io, pos, sects[i].data, size); // FIXME: check for errors and premature EOF pos += size; sdatapos += size; @@ -528,10 +543,12 @@ bool d88_format::load(util::random_read &io, uint32_t form_factor, const std::ve sects[i].data = nullptr; } - if(density == 0x40) - build_pc_track_fm(track, head, image, cell_count / 2, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); - else - build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); + if(head < img_heads) { + if(density == 0x40) + build_pc_track_fm(track, head, image, cell_count / 2, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); + else + build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); + } } return true; diff --git a/src/lib/formats/dcp_dsk.cpp b/src/lib/formats/dcp_dsk.cpp index f7740a0ea29..dfc9eea27dc 100644 --- a/src/lib/formats/dcp_dsk.cpp +++ b/src/lib/formats/dcp_dsk.cpp @@ -54,8 +54,7 @@ int dcp_format::identify(util::random_read &io, uint32_t form_factor, const std: int heads, tracks, spt, bps, count_tracks = 0; bool is_hdb = false; - size_t actual; - io.read_at(0, h, 0xa2, actual); + /*auto const [err, actual] =*/ read_at(io, 0, h, 0xa2); // FIXME: check for errors and premature EOF // First byte is the disk format (see below in load() for details) switch (h[0]) @@ -119,12 +118,11 @@ int dcp_format::identify(util::random_read &io, uint32_t form_factor, const std: bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; uint8_t h[0xa2]; int heads, tracks, spt, bps; bool is_hdb = false; - io.read_at(0, h, 0xa2, actual); + /*auto const [err, actual] =*/ read_at(io, 0, h, 0xa2); // FIXME: check for errors and premature EOF // First byte is the disk format: switch (h[0]) @@ -221,7 +219,7 @@ bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::ve for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { - io.read_at(0xa2 + bps * spt * (track * heads + head), sect_data, bps * spt, actual); + /*auto const [err, actual] =*/ read_at(io, 0xa2 + bps * spt * (track * heads + head), sect_data, bps * spt); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { @@ -241,7 +239,7 @@ bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::ve 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.read_at(0xa2, sect_data, 128 * spt, actual); + /*auto const [err, actual] =*/ read_at(io, 0xa2, sect_data, 128 * spt); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { @@ -258,7 +256,7 @@ bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::ve 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.read_at(0xa2 + 128 * spt, sect_data, bps * spt, actual); + /*auto const [err, actual] =*/ read_at(io, 0xa2 + 128 * spt, sect_data, bps * spt); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { @@ -279,7 +277,7 @@ bool dcp_format::load(util::random_read &io, uint32_t form_factor, const std::ve for (int track = 1; track < tracks; track++) for (int head = 0; head < heads; head++) { - io.read_at(data_offs + bps * spt * ((track - 1) * heads + head), sect_data, bps * spt, actual); + /*auto const [err, actual] =*/ read_at(io, data_offs + bps * spt * ((track - 1) * heads + head), sect_data, bps * spt); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { diff --git a/src/lib/formats/dfi_dsk.cpp b/src/lib/formats/dfi_dsk.cpp index a0d216002bd..e2ea1fda0e3 100644 --- a/src/lib/formats/dfi_dsk.cpp +++ b/src/lib/formats/dfi_dsk.cpp @@ -18,6 +18,8 @@ #include "osdcore.h" // osd_printf_* +#include <tuple> + #define NUMBER_OF_MULTIREADS 3 // thresholds for brickwall windowing @@ -63,16 +65,23 @@ bool dfi_format::supports_save() const noexcept int dfi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { char sign[4]; - size_t actual; - io.read_at(0, sign, 4, actual); + auto const [err, actual] = read_at(io, 0, sign, 4); + if(err || (4 != actual)) { + return 0; + } return memcmp(sign, "DFE2", 4) ? 0 : FIFID_SIGN; } bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; + char sign[4]; - io.read_at(0, sign, 4, actual); + std::tie(err, actual) = read_at(io, 0, sign, 4); + if(err || (4 != actual)) { + return false; + } if(memcmp(sign, "DFER", 4) == 0) { osd_printf_error("dfi_dsk: Old type Discferret image detected; the MAME Discferret decoder will not handle this properly, bailing out!\n"); return false; @@ -89,7 +98,7 @@ bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve [[maybe_unused]] int rpm=360; // drive rpm while(pos < size) { uint8_t h[10]; - io.read_at(pos, h, 10, actual); + std::tie(err, actual) = read_at(io, pos, h, 10); // FIXME: check for errors and premature EOF uint16_t track = get_u16be(&h[0]); uint16_t head = get_u16be(&h[2]); // Ignore sector @@ -105,7 +114,7 @@ bool dfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve data.resize(tsize); pos += 10; // skip the header, we already read it - io.read_at(pos, &data[0], tsize, actual); + std::tie(err, actual) = read_at(io, pos, &data[0], tsize); // FIXME: check for errors and premature EOF 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/dim_dsk.cpp b/src/lib/formats/dim_dsk.cpp index 52d3dfc1566..1f0902c2859 100644 --- a/src/lib/formats/dim_dsk.cpp +++ b/src/lib/formats/dim_dsk.cpp @@ -13,6 +13,8 @@ #include "ioprocs.h" #include <cstring> +#include <tuple> + dim_format::dim_format() { @@ -36,9 +38,9 @@ const char *dim_format::extensions() const noexcept int dim_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[16]; - - size_t actual; - io.read_at(0xab, h, 16, actual); + auto const [err, actual] = read_at(io, 0xab, h, 16); + if(err || (16 != actual)) + return 0; if(strncmp((const char *)h, "DIFC HEADER", 11) == 0) return FIFID_SIGN; @@ -48,13 +50,16 @@ int dim_format::identify(util::random_read &io, uint32_t form_factor, const std: bool dim_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; 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.read_at(0, &h, 1, actual); + std::tie(err, actual) = read_at(io, 0, &h, 1); + if (err || (1 != actual)) + return false; int spt, gap3, bps, size; switch(h) { @@ -114,7 +119,7 @@ bool dim_format::load(util::random_read &io, uint32_t form_factor, const std::ve sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = §_data[sdatapos]; - io.read_at(offset, sects[i].data, bps, actual); + std::tie(err, actual) = read_at(io, offset, sects[i].data, bps); // FIXME: check for errors and premature EOF offset += bps; sdatapos += bps; } diff --git a/src/lib/formats/dip_dsk.cpp b/src/lib/formats/dip_dsk.cpp index ecbd12bde1e..3ef8261d1da 100644 --- a/src/lib/formats/dip_dsk.cpp +++ b/src/lib/formats/dip_dsk.cpp @@ -72,8 +72,7 @@ bool dip_format::load(util::random_read &io, uint32_t form_factor, const std::ve for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { - size_t actual; - io.read_at(0x100 + bps * spt * (track * heads + head), sect_data, bps * spt, actual); + /*auto const [err, actual] =*/ read_at(io, 0x100 + bps * spt * (track * heads + head), sect_data, bps * spt); // FIXME: check for errors and premature EOF for (int i = 0; i < spt; i++) { diff --git a/src/lib/formats/dmk_dsk.cpp b/src/lib/formats/dmk_dsk.cpp index 68257ff1f2b..d02401b56cf 100644 --- a/src/lib/formats/dmk_dsk.cpp +++ b/src/lib/formats/dmk_dsk.cpp @@ -8,7 +8,7 @@ TODO: - Add write/format support. -- Check support on other drivers besides msx. +- Check support on other drivers besides MSX. *********************************************************************/ @@ -18,14 +18,18 @@ TODO: #include "ioprocs.h" #include "multibyte.h" +#include <tuple> + namespace { +constexpr int HEADER_SIZE = 16; + uint32_t wide_fm(uint16_t val) { uint32_t res = 0; for (int i = 15; i >= 0; i--) { - res |= (util::BIT(val, i) << (i*2 + 1)); + res |= (util::BIT(val, i) << (i * 2 + 1)); } return res; } @@ -34,7 +38,7 @@ uint32_t data_to_wide_fm(uint8_t val) { uint16_t res = 0xaaaa; // clock for (int i = 7; i >= 0; i--) { - res |= (util::BIT(val, i) << i*2); // data + res |= (util::BIT(val, i) << i * 2); // data } return wide_fm(res); } @@ -72,14 +76,17 @@ int dmk_format::identify(util::random_read &io, uint32_t form_factor, const std: if (io.length(size)) return 0; - const int header_size = 16; - uint8_t header[header_size]; + std::error_condition err; size_t actual; - io.read_at(0, header, header_size, actual); - int tracks = header[1]; - int track_size = get_u16le(&header[2]); - int heads = (header[4] & 0x10) ? 1 : 2; + uint8_t header[HEADER_SIZE]; + std::tie(err, actual) = read_at(io, 0, header, HEADER_SIZE); + if (err || (HEADER_SIZE != actual)) + return 0; + + const int tracks_from_header = header[1]; + const int track_size = get_u16le(&header[2]); + const int heads = util::BIT(header[4], 4) ? 1 : 2; // The first header byte must be 00 or FF if (header[0] != 0x00 && header[0] != 0xff) @@ -87,66 +94,73 @@ int dmk_format::identify(util::random_read &io, uint32_t form_factor, const std: return 0; } - // Bytes C-F must be zero - if (header[0x0c] != 0 || header[0xd] != 0 || header[0xe] != 0 || header[0xf] != 0) + // Verify reserved/unsupported header bytes + for (int i = 5; i < 0x10; i++) { - return 0; + if (header[i] != 0x00) + return 0; } // Check track size within limits - if (track_size < 0x80 || track_size > 0x3FFF ) - { + if (track_size < 0x80 || track_size > 0x3fff) return 0; - } - if (size == header_size + heads * tracks * track_size) + const int tracks_in_file = (size - HEADER_SIZE) / (heads * track_size); + for (int track = 0; track < tracks_in_file; track++) { - return FIFID_STRUCT|FIFID_SIZE; - } + for (int head = 0; head < heads; head++) + { + // Read track + std::vector<uint8_t> track_data(track_size); + std::tie(err, actual) = read_at(io, HEADER_SIZE + (heads * track + head) * track_size, &track_data[0], track_size); + if (err || track_size != actual) + return 0; - return 0; + // Verify idam entries + for (int idam_index = 0; idam_index < 64; idam_index++) + { + const uint16_t idam_entry = get_u16le(&track_data[2 * idam_index]); + if (idam_entry == 0x0000) + continue; + const uint16_t idam_offset = idam_entry & 0x3fff; + if (idam_offset >= track_size) + return 0; + if (track_data[idam_offset] != 0xfe) + return 0; + } + } + } + if (size == HEADER_SIZE + heads * tracks_from_header * track_size) + return FIFID_HINT|FIFID_SIZE; + else + return FIFID_HINT; } bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; - const int header_size = 16; - uint8_t header[header_size]; - io.read_at(0, header, header_size, actual); + uint64_t size; + if (io.length(size)) + return false; + + uint8_t header[HEADER_SIZE]; + std::tie(err, actual) = read_at(io, 0, header, HEADER_SIZE); + if (err || (HEADER_SIZE != actual)) + return false; - const int tracks = header[1]; const int track_size = get_u16le(&header[2]); - const int heads = (header[4] & 0x10) ? 1 : 2; - const bool is_sd = (header[4] & 0x40) ? true : false; + const int heads = util::BIT(header[4], 4) ? 1 : 2; + const bool is_sd = util::BIT(header[4], 6); + const int tracks = (size - HEADER_SIZE) / (heads * track_size); - auto variant = floppy_image::SSDD; - if (is_sd) - { - if (heads == 2) - { - variant = floppy_image::DSSD; - } - else - { - variant = floppy_image::SSSD; - } - } - else - { - if (heads == 2) - { - variant = floppy_image::DSDD; - } - else - { - variant = floppy_image::SSDD; - } - } + const auto variant = is_sd ? (heads == 2 ? floppy_image::DSSD : floppy_image::SSSD) + : (heads == 2 ? floppy_image::DSDD : floppy_image::SSDD); image.set_variant(variant); - int fm_stride = is_sd ? 1 : 2; + const int fm_stride = is_sd ? 1 : 2; for (int track = 0; track < tracks; track++) { @@ -155,15 +169,17 @@ bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::ve int fm_loss = 0; std::vector<uint8_t> track_data(track_size); std::vector<uint32_t> raw_track_data; - int mark_location[64*2+1]; - uint8_t mark_value[64*2+1]; - bool mark_is_mfm[64*2+1]; + int mark_location[64 * 2 + 1]; + uint8_t mark_value[64 * 2 + 1]; + bool mark_is_mfm[64 * 2 + 1]; int iam_location = -1; // Read track - io.read_at(header_size + (heads * track + head) * track_size, &track_data[0], track_size, actual); + std::tie(err, actual) = read_at(io, HEADER_SIZE + (heads * track + head) * track_size, &track_data[0], track_size); + if (err || track_size != actual) + return false; - for (int i = 0; i < 64*2+1; i++) + for (int i = 0; i < 64 * 2 + 1; i++) { mark_location[i] = -1; mark_value[i] = 0xfe; @@ -174,10 +190,10 @@ bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::ve // Find IDAM/DAM locations uint16_t track_header_offset = 0; uint16_t track_offset = get_u16le(&track_data[track_header_offset]) & 0x3fff; - bool idam_is_mfm = (track_data[track_header_offset + 1] & 0x80) ? true : false; + bool idam_is_mfm = util::BIT(track_data[track_header_offset + 1], 7); track_header_offset += 2; - while ( track_offset != 0 && track_offset >= 0x83 && track_offset < track_size && track_header_offset < 0x80 ) + while (track_offset != 0 && track_offset >= 0x83 && track_offset < track_size && track_header_offset < 0x80) { // Assume 3 bytes before IDAM pointers are the start of IDAM indicators int mark_offset = idam_is_mfm ? 3 : 0; @@ -188,11 +204,11 @@ bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::ve int stride = idam_is_mfm ? 1 : fm_stride; // Scan for DAM location - for (int i = track_offset + 10*stride; i < track_offset + 53*stride; i++) + for (int i = track_offset + 10 * stride; i < track_offset + 53 * stride; i++) { if ((track_data[i] >= 0xf8 && track_data[i] <= 0xfb)) { - if (!idam_is_mfm || (track_data[i-1] == 0xa1 && track_data[i-2] == 0xa1)) + if (!idam_is_mfm || get_u16le(&track_data[i - 2]) == 0xa1a1) { mark_location[mark_count] = i - mark_offset; mark_value[mark_count] = track_data[i]; @@ -204,7 +220,7 @@ bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::ve } } - idam_is_mfm = (track_data[track_header_offset + 1] & 0x80) ? true : false; + idam_is_mfm = util::BIT(track_data[track_header_offset + 1], 7); track_offset = get_u16le(&track_data[track_header_offset]) & 0x3fff; track_header_offset += 2; } @@ -216,10 +232,10 @@ bool dmk_format::load(util::random_read &io, uint32_t form_factor, const std::ve } // Find IAM location - for(int i = mark_location[0] - 1; i >= 3; i--) + for (int i = mark_location[0] - 1; i >= 3; i--) { // It's usually 3 bytes but several dumped tracks seem to contain only 2 bytes - if (track_data[i] == 0xfc && (is_sd || (track_data[i-1] == 0xc2 && track_data[i-2] == 0xc2))) + if (track_data[i] == 0xfc && (is_sd || get_u16le(&track_data[i - 2]) == 0xc2c2)) { iam_location = i - (is_sd ? 0 : 3); break; diff --git a/src/lib/formats/ds9_dsk.cpp b/src/lib/formats/ds9_dsk.cpp index 396a6ae3235..c0cbf0dccbc 100644 --- a/src/lib/formats/ds9_dsk.cpp +++ b/src/lib/formats/ds9_dsk.cpp @@ -109,8 +109,7 @@ bool ds9_format::load(util::random_read &io, uint32_t form_factor, const std::ve { for (int head = 0; head < head_count; head++) { - size_t actual; - io.read_at((track * head_count + head) * track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ read_at(io, (track * head_count + head) * track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(ds9_desc, track, head, sectors, sector_count, 104000, image); } } diff --git a/src/lib/formats/dsk_dsk.cpp b/src/lib/formats/dsk_dsk.cpp index adfbe7735ed..e10e94f80be 100644 --- a/src/lib/formats/dsk_dsk.cpp +++ b/src/lib/formats/dsk_dsk.cpp @@ -311,13 +311,14 @@ bool dsk_format::supports_save() const noexcept int dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[16]; - - size_t actual; - io.read_at(0, &header, sizeof(header), actual); - if ( memcmp( header, DSK_FORMAT_HEADER, 8 ) ==0) { + auto const [err, actual] = read_at(io, 0, &header, sizeof(header)); + if (err) { + return 0; + } + if ((8 <= actual) && !memcmp(header, DSK_FORMAT_HEADER, 8)) { return FIFID_SIGN; } - if ( memcmp( header, EXT_FORMAT_HEADER, 16 ) ==0) { + if ((16 <= actual) && !memcmp(header, EXT_FORMAT_HEADER, 16)) { return FIFID_SIGN; } return 0; @@ -356,8 +357,6 @@ struct sector_header bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; - uint8_t header[0x100]; bool extendformat = false; @@ -365,7 +364,7 @@ bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::ve if (io.length(image_size)) return false; - io.read_at(0, &header, sizeof(header), actual); + read_at(io, 0, &header, sizeof(header)); // FIXME: check for errors and premature EOF if ( memcmp( header, EXT_FORMAT_HEADER, 16 ) ==0) { extendformat = true; } @@ -431,7 +430,7 @@ bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(track_offsets[(track<<1)+side] >= image_size) continue; track_header tr; - io.read_at(track_offsets[(track<<1)+side], &tr, sizeof(tr), actual); + read_at(io, track_offsets[(track<<1)+side], &tr, sizeof(tr)); // FIXME: check for errors and premature EOF // skip if there are no sectors in this track if (tr.number_of_sector == 0) @@ -441,7 +440,7 @@ bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::ve int first_sector_code = -1; for(int j=0;j<tr.number_of_sector;j++) { sector_header sector; - io.read_at(track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector), actual); + read_at(io, track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector)); // FIXME: check for errors and premature EOF if (j == 0) first_sector_code = sector.sector_size_code; @@ -460,7 +459,7 @@ bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::ve for(int j=0;j<tr.number_of_sector;j++) { sector_header sector; - io.read_at(track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector), actual); + read_at(io, track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), §or, sizeof(sector)); // FIXME: check for errors and premature EOF sects[j].track = sector.track; sects[j].head = sector.side; @@ -483,7 +482,7 @@ bool dsk_format::load(util::random_read &io, uint32_t form_factor, const std::ve if(!(sector.fdc_status_reg1 & 0x04)) { sects[j].data = sect_data + sdatapos; - io.read_at(pos, sects[j].data, sects[j].actual_size, actual); + read_at(io, pos, sects[j].data, sects[j].actual_size); // FIXME: check for errors and premature EOF sdatapos += sects[j].actual_size; } else diff --git a/src/lib/formats/dvk_mx_dsk.cpp b/src/lib/formats/dvk_mx_dsk.cpp index 981bed010e7..c384dc38e00 100644 --- a/src/lib/formats/dvk_mx_dsk.cpp +++ b/src/lib/formats/dvk_mx_dsk.cpp @@ -23,65 +23,45 @@ #include "ioprocs.h" #include "multibyte.h" +constexpr uint32_t ID_PATTERN = 0xaaaaffaf; 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 }, - /* 02 */ { FM, 0xf3, 1 }, // word 0x00f3 - /* 05 */ { FM, 0x00, 1 }, - /* 04 */ { TRACK_ID_FM }, // track number word - /* 05 */ { SECTOR_LOOP_START, 0, 10 }, // 11 sectors + /* 02 */ { FM, 0x00, 1 }, + /* 03 */ { FM, 0xf3, 1 }, // word 0x00f3 + /* 04 */ { FM, 0x00, 1 }, + /* 05 */ { TRACK_ID_FM }, // track number word + /* 06 */ { SECTOR_LOOP_START, 0, 10 }, // 11 sectors /* 07 */ { SECTOR_DATA_MX, -1 }, - /* 10 */ { SECTOR_LOOP_END }, - /* 13 */ { FM, 0x83, 1 }, + /* 08 */ { SECTOR_LOOP_END }, + /* 09 */ { FM, 0x83, 1 }, + /* 10 */ { OFFSET_ID_FM }, + /* 11 */ { FM, 0x83, 1 }, /* 12 */ { OFFSET_ID_FM }, - /* 15 */ { FM, 0x83, 1 }, + /* 13 */ { FM, 0x83, 1 }, /* 14 */ { OFFSET_ID_FM }, - /* 17 */ { FM, 0x83, 1 }, - /* 16 */ { OFFSET_ID_FM }, - /* 18 */ { END } + /* 15 */ { END } }; const floppy_image_format_t::desc_e dvk_mx_format::dvk_mx_old_desc[] = { /* 01 */ { FM, 0x00, 30*2 }, - /* 03 */ { FM, 0x00, 1 }, - /* 02 */ { FM, 0xf3, 1 }, // word 0x00f3 - /* 05 */ { FM, 0x00, 1 }, - /* 04 */ { TRACK_ID_FM }, // track number word + /* 02 */ { FM, 0x00, 1 }, + /* 03 */ { FM, 0xf3, 1 }, // word 0x00f3 + /* 04 */ { FM, 0x00, 1 }, + /* 05 */ { TRACK_ID_FM }, // track number word /* 06 */ { SECTOR_LOOP_START, 0, 10 }, // 11 sectors /* 07 */ { SECTOR_DATA_MX, -1 }, - /* 10 */ { SECTOR_LOOP_END }, - /* 13 */ { FM, 0x83, 1 }, - /* 11 */ { FM, 0x01, 1 }, - /* 15 */ { FM, 0x83, 1 }, - /* 14 */ { FM, 0x01, 1 }, - /* 16 */ { END } + /* 08 */ { SECTOR_LOOP_END }, + /* 09 */ { FM, 0x00, 1 }, + /* 10 */ { FM, 0116, 1 }, + /* 11 */ { FM, 0x00, 4*2 }, // four 0x0000 words + /* 12 */ { END } }; dvk_mx_format::dvk_mx_format() { } -const char *dvk_mx_format::name() const noexcept -{ - return "mx"; -} - -const char *dvk_mx_format::description() const noexcept -{ - return "DVK MX: floppy image"; -} - -const char *dvk_mx_format::extensions() const noexcept -{ - return "mx"; -} - -bool dvk_mx_format::supports_save() const noexcept -{ - return false; -} - 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; @@ -95,17 +75,17 @@ void dvk_mx_format::find_size(util::random_read &io, uint8_t &track_count, uint8 { case 112640: track_count = 40; - sector_count = 11; + sector_count = MX_SECTORS; head_count = 1; break; case 225280: track_count = 40; - sector_count = 11; + sector_count = MX_SECTORS; head_count = 2; break; case 450560: track_count = 80; - sector_count = 11; + sector_count = MX_SECTORS; head_count = 2; break; default: @@ -123,8 +103,7 @@ int dvk_mx_format::identify(util::random_read &io, uint32_t form_factor, const s if (track_count) { uint8_t sectdata[512]; - size_t actual; - io.read_at(512, sectdata, 512, actual); + /*auto const [err, actual] =*/ read_at(io, 512, sectdata, 512); // FIXME: check for errors and premature EOF // check value in RT-11 home block. see src/tools/imgtool/modules/rt11.cpp if (get_u16le(§data[0724]) == 6) return FIFID_SIGN|FIFID_SIZE; @@ -143,22 +122,21 @@ bool dvk_mx_format::load(util::random_read &io, uint32_t form_factor, const std: find_size(io, track_count, head_count, sector_count); if (track_count == 0) return false; - uint8_t sectdata[11 * 256]; - desc_s sectors[11]; + uint8_t sectdata[MX_SECTORS * MX_SECTOR_SIZE]; + desc_s sectors[MX_SECTORS]; for (int i = 0; i < sector_count; i++) { - sectors[i].data = sectdata + 256 * i; - sectors[i].size = 256; + sectors[i].data = sectdata + MX_SECTOR_SIZE * i; + sectors[i].size = MX_SECTOR_SIZE; sectors[i].sector_id = i; } - int track_size = sector_count * 256; + int track_size = sector_count * MX_SECTOR_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); + /*auto const [err, actual] =*/ read_at(io, (track * head_count + head) * track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(dvk_mx_new_desc, track, head, sectors, sector_count, 45824, image); } } @@ -182,4 +160,65 @@ bool dvk_mx_format::load(util::random_read &io, uint32_t form_factor, const std: return true; } +bool dvk_mx_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const +{ + int tracks; + int heads; + bool res = false; + image.get_actual_geometry(tracks, heads); + + for (int cyl = 0; cyl < tracks; cyl++) + { + for (int head = 0; head < heads; head++) + { + auto bitstream = generate_bitstream_from_track(cyl, head, 4000, image, 0); + uint8_t sector_data[MX_SECTORS * MX_SECTOR_SIZE]; + if (get_next_sector(bitstream, sector_data)) + { + unsigned const offset_in_image = (cyl * heads + head) * MX_SECTOR_SIZE * MX_SECTORS; + res = true; + // FIXME: check for errors + /*auto const [err, actual] =*/ write_at(io, offset_in_image, sector_data, MX_SECTOR_SIZE * MX_SECTORS); + } + } + } + return res; +} + +bool dvk_mx_format::get_next_sector(const std::vector<bool> &bitstream, uint8_t *sector_data) +{ + uint32_t sr = 0; + int pos = 0; + while (pos < bitstream.size() && sr != ID_PATTERN) + { + sr = (sr << 1) | bitstream[pos]; + pos++; + } + if (pos == bitstream.size()) + { + // End of track reached + return false; + } + unsigned to_dump = MX_SECTORS * (MX_SECTOR_SIZE + 2); + pos += 32; // skip track ID + for (unsigned i = 0, k = 0; i < to_dump && pos < bitstream.size(); i++) + { + uint8_t byte = 0; + unsigned j; + for (j = 0; j < 8 && pos < bitstream.size(); j++) + { + bool bit = bitstream[pos + 1]; + pos += 2; + byte <<= 1; + byte |= bit; + } + if (j == 8 && (i % (MX_SECTOR_SIZE + 2)) < MX_SECTOR_SIZE) + { + sector_data[k ^ 1] = byte; + k++; + } + } + return true; +} + const dvk_mx_format FLOPPY_DVK_MX_FORMAT; diff --git a/src/lib/formats/dvk_mx_dsk.h b/src/lib/formats/dvk_mx_dsk.h index 83f93fd0878..b0d64deab9f 100644 --- a/src/lib/formats/dvk_mx_dsk.h +++ b/src/lib/formats/dvk_mx_dsk.h @@ -19,17 +19,22 @@ public: virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + virtual bool save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const override; - virtual const char *name() const noexcept override; - virtual const char *description() const noexcept override; - virtual const char *extensions() const noexcept override; - virtual bool supports_save() const noexcept override; + virtual const char *name() const noexcept override { return "mx"; } + virtual const char *description() const noexcept override { return "DVK MX disk image"; } + virtual const char *extensions() const noexcept override { return "mx"; } + virtual bool supports_save() const noexcept override { return true; } static const desc_e dvk_mx_old_desc[]; static const desc_e dvk_mx_new_desc[]; private: + static constexpr unsigned MX_SECTORS = 11; + static constexpr unsigned MX_SECTOR_SIZE = 256; + static void find_size(util::random_read &io, uint8_t &track_count, uint8_t &head_count, uint8_t §or_count); + static bool get_next_sector(const std::vector<bool> &bitstream , uint8_t *sector_data); }; extern const dvk_mx_format FLOPPY_DVK_MX_FORMAT; diff --git a/src/lib/formats/esq16_dsk.cpp b/src/lib/formats/esq16_dsk.cpp index a7e181b2cc7..f487e835665 100644 --- a/src/lib/formats/esq16_dsk.cpp +++ b/src/lib/formats/esq16_dsk.cpp @@ -113,8 +113,7 @@ bool esqimg_format::load(util::random_read &io, uint32_t form_factor, const std: int track_size = sector_count*512; 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); + /*auto const [err, actual] =*/ read_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(esq_10_desc, track, head, sectors, sector_count, 110528, image); } } @@ -145,8 +144,7 @@ bool esqimg_format::save(util::random_read_write &io, const std::vector<uint32_t 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); - size_t actual; - io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors } } diff --git a/src/lib/formats/esq8_dsk.cpp b/src/lib/formats/esq8_dsk.cpp index fb3bdb112d6..b7225d839a9 100644 --- a/src/lib/formats/esq8_dsk.cpp +++ b/src/lib/formats/esq8_dsk.cpp @@ -132,8 +132,7 @@ bool esq8img_format::load(util::random_read &io, uint32_t form_factor, const std { for(int head=0; head < head_count; head++) { - size_t actual; - io.read_at((track*head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ read_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(esq_6_desc, track, head, sectors, sector_count, 109376, image); } } @@ -180,8 +179,7 @@ bool esq8img_format::save(util::random_read_write &io, const std::vector<uint32_ return false; } - size_t actual; - io.write_at(file_offset, sectors[sector].data(), sector_expected_size, actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, sectors[sector].data(), sector_expected_size); // FIXME: check for errors file_offset += sector_expected_size; } } diff --git a/src/lib/formats/fc100_cas.cpp b/src/lib/formats/fc100_cas.cpp index da2247d49b5..d991ce8de6a 100644 --- a/src/lib/formats/fc100_cas.cpp +++ b/src/lib/formats/fc100_cas.cpp @@ -104,7 +104,7 @@ static int fc100_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int fc100_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int fc100_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return fc100_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/fdd_dsk.cpp b/src/lib/formats/fdd_dsk.cpp index fc0741f2f5a..7519eb593dd 100644 --- a/src/lib/formats/fdd_dsk.cpp +++ b/src/lib/formats/fdd_dsk.cpp @@ -62,10 +62,11 @@ const char *fdd_format::extensions() const noexcept int fdd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[7]; - size_t actual; - io.read_at(0, h, 7, actual); + auto const [err, actual] = read_at(io, 0, h, 7); // FIXME: should it really be reading six bytes? also check for premature EOF. + if (err) + return false; - if (strncmp((const char *)h, "VFD1.0", 6) == 0) + if (memcmp(h, "VFD1.0", 6) == 0) return FIFID_SIGN; return 0; @@ -92,8 +93,7 @@ bool fdd_format::load(util::random_read &io, uint32_t form_factor, const std::ve for (int sect = 0; sect < 26; sect++) { // read sector map for this sector - size_t actual; - io.read_at(pos, hsec, 0x0c, actual); + /*auto const [err, actual] =*/ read_at(io, pos, hsec, 0x0c); // FIXME: check for errors and premature EOF pos += 0x0c; if (hsec[0] == 0xff) // unformatted/unused sector @@ -125,11 +125,10 @@ bool fdd_format::load(util::random_read &io, uint32_t form_factor, const std::ve 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.read_at(sec_offs[cur_sec_map], sect_data + cur_pos, sector_size, actual); + /*auto const [err, actual] =*/ read_at(io, sec_offs[cur_sec_map], sect_data + cur_pos, sector_size); // FIXME: check for errors and premature EOF sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; diff --git a/src/lib/formats/fdos_dsk.cpp b/src/lib/formats/fdos_dsk.cpp index 2980376160e..138ad986011 100644 --- a/src/lib/formats/fdos_dsk.cpp +++ b/src/lib/formats/fdos_dsk.cpp @@ -39,9 +39,12 @@ #include "fdos_dsk.h" #include "imageutl.h" -#include "multibyte.h" #include "ioprocs.h" +#include "multibyte.h" + +#include <tuple> + namespace { @@ -116,7 +119,7 @@ int fdos_format::find_size(util::random_read &io, uint32_t form_factor, const st // 00330 2403 DE OB RESTRT LDX PROGX // Should be $BD and $DE respectively // There could be additional variations - ec = io.read_at(0, &boot0, f.sector_base_size, actual); + std::tie(ec, actual) = read_at(io, 0, &boot0, f.sector_base_size); if (ec || actual != f.sector_base_size) return -1; if (boot0[0] != 0xbd && boot0[3] != 0xde) @@ -129,7 +132,7 @@ int fdos_format::find_size(util::random_read &io, uint32_t form_factor, const st form_factor); // Directory entries start at Track 2 Sector 0 - ec = io.read_at(2 * f.sector_count * f.sector_base_size, &info, sizeof(struct fdos_formats::dirent_entry_fdos), actual); + std::tie(ec, actual) = read_at(io, 2 * f.sector_count * f.sector_base_size, &info, sizeof(struct fdos_formats::dirent_entry_fdos)); if (ec || actual != sizeof(struct fdos_formats::dirent_entry_fdos)) continue; diff --git a/src/lib/formats/flacfile.cpp b/src/lib/formats/flacfile.cpp index f3ccb676e52..c594a809a8e 100644 --- a/src/lib/formats/flacfile.cpp +++ b/src/lib/formats/flacfile.cpp @@ -16,10 +16,27 @@ #include <new> -static constexpr int MAX_CHANNELS = 8; +namespace { +constexpr int MAX_CHANNELS = 8; -static cassette_image::error flacfile_identify(cassette_image *cassette, cassette_image::Options *opts) + +// Copied from cassimg.cpp; put somewhere central? +/********************************************************************* + helper code +*********************************************************************/ +constexpr double map_double(double d, uint64_t low, uint64_t high, uint64_t value) +{ + return d * (value - low) / (high - low); +} + +constexpr size_t waveform_bytes_per_sample(int waveform_flags) +{ + return size_t(1 << ((waveform_flags & 0x06) / 2)); +} + + +cassette_image::error flacfile_identify(cassette_image *cassette, cassette_image::Options *opts) { cassette->get_raw_cassette_image()->seek(0, SEEK_SET); flac_decoder decoder(*cassette->get_raw_cassette_image()); @@ -42,7 +59,7 @@ static cassette_image::error flacfile_identify(cassette_image *cassette, cassett } -static cassette_image::error flacfile_load(cassette_image *cassette) +cassette_image::error flacfile_load(cassette_image *cassette) { cassette->get_raw_cassette_image()->seek(0, SEEK_SET); flac_decoder decoder(*cassette->get_raw_cassette_image()); @@ -73,10 +90,63 @@ static cassette_image::error flacfile_load(cassette_image *cassette) } +cassette_image::error flacfile_save(cassette_image *cassette, const cassette_image::Info *info) +{ + if (info->channels > MAX_CHANNELS) + return cassette_image::error::INVALID_IMAGE; + + cassette->get_raw_cassette_image()->seek(0, SEEK_SET); + flac_encoder encoder; + encoder.set_num_channels(info->channels); + encoder.set_sample_rate(info->sample_frequency); + if (!encoder.reset(*cassette->get_raw_cassette_image())) + return cassette_image::error::INTERNAL; + + size_t samples_saved = 0; + int16_t buffer[MAX_CHANNELS][4096]; + int16_t *buffer_ptr[MAX_CHANNELS]; + const size_t bytes_per_sample = waveform_bytes_per_sample(cassette_image::WAVEFORM_16BIT); + const size_t sample_spacing = bytes_per_sample * info->channels; + const double sample_period = info->sample_count / (double) info->sample_frequency; + + for (int channel = 0; channel < MAX_CHANNELS; channel++) + { + buffer_ptr[channel] = &buffer[channel][0]; + } + + while (samples_saved < info->sample_count) + { + size_t chunk_sample_count = std::min(sizeof(buffer) / sample_spacing, (info->sample_count - samples_saved)); + double chunk_sample_period = map_double(sample_period, 0, info->sample_count, chunk_sample_count); + double chunk_time_index = map_double(sample_period, 0, info->sample_count, samples_saved); + + for (int channel = 0; channel < info->channels; channel++) + { + cassette_image::error err = cassette->get_samples(channel, chunk_time_index, chunk_sample_period, + chunk_sample_count, sample_spacing, &buffer[channel * bytes_per_sample], cassette_image::WAVEFORM_16BIT); + + if (err != cassette_image::error::SUCCESS) + return err; + } + + if (!encoder.encode(buffer_ptr, chunk_sample_count)) + return cassette_image::error::INTERNAL; + + samples_saved += chunk_sample_count; + } + + encoder.finish(); + + return cassette_image::error::SUCCESS; +} + +} // anonymous namespace + + const cassette_image::Format cassette_image::flacfile_format = { "flac", flacfile_identify, flacfile_load, - nullptr + flacfile_save }; diff --git a/src/lib/formats/flex_dsk.cpp b/src/lib/formats/flex_dsk.cpp index 778e6c990b9..11a72963471 100644 --- a/src/lib/formats/flex_dsk.cpp +++ b/src/lib/formats/flex_dsk.cpp @@ -91,12 +91,11 @@ int flex_format::find_size(util::random_read &io, uint32_t form_factor, const st return -1; uint8_t boot0[256], boot1[256]; - size_t actual; // Look at the boot sector. // Density, sides, link?? - io.read_at(256 * 0, &boot0, sizeof(boot0), actual); - io.read_at(256 * 1, &boot1, sizeof(boot1), actual); + read_at(io, 256 * 0, &boot0, sizeof(boot0)); // FIXME: check for errors and premature EOF + read_at(io, 256 * 1, &boot1, sizeof(boot1)); // FIXME: check for errors and premature EOF 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); @@ -129,7 +128,7 @@ int flex_format::find_size(util::random_read &io, uint32_t form_factor, const st if (f.sector_base_size == 128) { // FLEX 1.0: Look at the system information sector. sysinfo_sector_flex10 info; - io.read_at(f.sector_base_size * 2, &info, sizeof(struct sysinfo_sector_flex10), actual); + read_at(io, f.sector_base_size * 2, &info, sizeof(struct sysinfo_sector_flex10)); // FIXME: check for errors and premature EOF 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 / f.sector_base_size, (uint32_t)size % f.sector_base_size, form_factor); @@ -142,7 +141,7 @@ int flex_format::find_size(util::random_read &io, uint32_t form_factor, const st } else { // FLEX 2+: Look at the system information sector. sysinfo_sector info; - io.read_at(f.sector_base_size * 2, &info, sizeof(struct sysinfo_sector), actual); + read_at(io, f.sector_base_size * 2, &info, sizeof(struct sysinfo_sector)); // FIXME: check for errors and premature EOF 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 / f.sector_base_size, (uint32_t)size % f.sector_base_size, form_factor); diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index ec978817a6e..fa4903447fb 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -39,6 +39,39 @@ floppy_image::~floppy_image() { } +void floppy_image::set_variant(uint32_t _variant) +{ + variant = _variant; + + // Initialize hard sectors + index_array.clear(); + + uint32_t sectors; + switch(variant) { + case SSDD16: + case SSQD16: + case DSDD16: + case DSQD16: + sectors = 16; + break; + default: + sectors = 0; + } + if(sectors) { + uint32_t sector_angle = 200000000/sectors; + for(int i = 1; i < sectors; i++) + index_array.push_back(i*sector_angle); + index_array.push_back((sectors-1)*sector_angle + sector_angle/2); + } +} + +void floppy_image::find_index_hole(uint32_t pos, uint32_t &last, uint32_t &next) const +{ + auto nexti = std::lower_bound(index_array.begin(), index_array.end(), pos+1); + next = nexti == index_array.end() ? 200000000 : *nexti; + last = nexti == index_array.begin() ? 0 : *--nexti; +} + void floppy_image::get_maximal_geometry(int &_tracks, int &_heads) const noexcept { _tracks = tracks; @@ -104,13 +137,30 @@ bool floppy_image::track_is_formatted(int track, int head, int subtrack) const n const char *floppy_image::get_variant_name(uint32_t form_factor, uint32_t variant) noexcept { switch(variant) { - case SSSD: return "Single side, single density"; - case SSDD: return "Single side, double density"; - case SSQD: return "Single side, quad density"; - case DSDD: return "Double side, double density"; - case DSQD: return "Double side, quad density"; - case DSHD: return "Double side, high density"; - case DSED: return "Double side, extended density"; + case SSSD: return "Single side, single density"; + case SSSD10: return "Single side, single density, 10-sector"; + case SSSD16: return "Single side, single density, 16-sector"; + case SSSD32: return "Single side, single density, 32-sector"; + case SSDD: return "Single side, double density"; + case SSDD10: return "Single side, double density, 10-sector"; + case SSDD16: return "Single side, double density, 16 hard sector"; + case SSDD32: return "Single side, double density, 32-sector"; + case SSQD: return "Single side, quad density"; + case SSQD10: return "Single side, quad density, 10-sector"; + case SSQD16: return "Single side, quad density, 16 hard sector"; + case DSSD: return "Double side, single density"; + case DSSD10: return "Double side, single density, 10-sector"; + case DSSD16: return "Double side, single density, 16-sector"; + case DSSD32: return "Double side, single density, 32-sector"; + case DSDD: return "Double side, double density"; + case DSDD10: return "Double side, double density, 10-sector"; + case DSDD16: return "Double side, double density, 16 hard sector"; + case DSDD32: return "Double side, double density, 32-sector"; + case DSQD: return "Double side, quad density"; + case DSQD10: return "Double side, quad density, 10-sector"; + case DSQD16: return "Double side, quad density, 16 hard sector"; + case DSHD: return "Double side, high density"; + case DSED: return "Double side, extended density"; } return "Unknown"; } @@ -864,7 +914,7 @@ void floppy_image_format_t::generate_track_from_bitstream(int track, int head, c normalize_times(dest, track_size*2); - if(splice >= 0 || splice < track_size) { + if(splice >= 0 && splice < track_size) { int splpos = uint64_t(200000000) * splice / track_size; image.set_write_splice_position(track, head, splpos, subtrack); } diff --git a/src/lib/formats/flopimg.h b/src/lib/formats/flopimg.h index 4098ab3d418..18cc17ea73b 100644 --- a/src/lib/formats/flopimg.h +++ b/src/lib/formats/flopimg.h @@ -525,14 +525,30 @@ public: //! Variants enum { - SSSD = 0x44535353, //!< "SSSD", Single-sided single-density - SSDD = 0x44445353, //!< "SSDD", Single-sided double-density - SSQD = 0x44515353, //!< "SSQD", Single-sided quad-density - DSSD = 0x44535344, //!< "DSSD", Double-sided single-density - DSDD = 0x44445344, //!< "DSDD", Double-sided double-density (720K in 3.5, 360K in 5.25) - DSQD = 0x44515344, //!< "DSQD", Double-sided quad-density (720K in 5.25, means DD+80 tracks) - DSHD = 0x44485344, //!< "DSHD", Double-sided high-density (1440K) - DSED = 0x44455344 //!< "DSED", Double-sided extra-density (2880K) + SSSD = 0x44535353, //!< "SSSD", Single-sided single-density + SSSD10 = 0x30315353, //!< "SS10", Single-sided single-density 10 hard sector + SSSD16 = 0x36315353, //!< "SS16", Single-sided single-density 16 hard sector + SSSD32 = 0x32335353, //!< "SS32", Single-sided single-density 32 hard sector + SSDD = 0x44445353, //!< "SSDD", Single-sided double-density + SSDD10 = 0x30314453, //!< "SD10", Single-sided double-density 10 hard sector + SSDD16 = 0x36314453, //!< "SD16", Single-sided double-density 16 hard sector + SSDD32 = 0x32334453, //!< "SD32", Single-sided double-density 32 hard sector + SSQD = 0x44515353, //!< "SSQD", Single-sided quad-density + SSQD10 = 0x30315153, //!< "SQ10", Single-sided quad-density 10 hard sector + SSQD16 = 0x36315153, //!< "SQ16", Single-sided quad-density 16 hard sector + DSSD = 0x44535344, //!< "DSSD", Double-sided single-density + DSSD10 = 0x30315344, //!< "DS10", Double-sided single-density 10 hard sector + DSSD16 = 0x36315344, //!< "DS16", Double-sided single-density 16 hard sector + DSSD32 = 0x32335344, //!< "DS32", Double-sided single-density 32 hard sector + DSDD = 0x44445344, //!< "DSDD", Double-sided double-density (720K in 3.5, 360K in 5.25) + DSDD10 = 0x30314444, //!< "DD10", Double-sided double-density 10 hard sector + DSDD16 = 0x36314444, //!< "DD16", Double-sided double-density 16 hard sector (360K in 5.25) + DSDD32 = 0x32334444, //!< "DD32", Double-sided double-density 32 hard sector + DSQD = 0x44515344, //!< "DSQD", Double-sided quad-density (720K in 5.25, means DD+80 tracks) + DSQD10 = 0x30315144, //!< "DQ10", Double-sided quad-density 10 hard sector + DSQD16 = 0x36315144, //!< "DQ16", Double-sided quad-density 16 hard sector (720K in 5.25, means DD+80 tracks) + DSHD = 0x44485344, //!< "DSHD", Double-sided high-density (1440K) + DSED = 0x44455344 //!< "DSED", Double-sided extra-density (2880K) }; //! Encodings @@ -542,6 +558,14 @@ public: M2FM = 0x4D32464D //!< "M2FM", modified modified frequency modulation }; + //! Sectoring + enum { + SOFT = 0x54464F53, //!< "SOFT", Soft-sectored + H10 = 0x20303148, //!< "H10 ", Hard 10-sectored + H16 = 0x20363148, //!< "H16 ", Hard 16-sectored + H32 = 0x20323348 //!< "H32 ", Hard 32-sectored (8 inch disk) + }; + // construction/destruction @@ -558,10 +582,25 @@ public: uint32_t get_form_factor() const noexcept { return form_factor; } //! @return the variant. uint32_t get_variant() const noexcept { return variant; } + //! @return the disk sectoring. + uint32_t get_sectoring() const noexcept { return sectoring; } //! @param v the variant. - void set_variant(uint32_t v) { variant = v; } + void set_variant(uint32_t v); //! @param v the variant. - void set_form_variant(uint32_t f, uint32_t v) { if(form_factor == FF_UNKNOWN) form_factor = f; variant = v; } + void set_form_variant(uint32_t f, uint32_t v) { if(form_factor == FF_UNKNOWN) form_factor = f; set_variant(v); } + //! @param s the sectoring. + void set_sectoring(uint32_t s) { sectoring = s; } + + //! Find most recent and next index hole for provided angular position. + //! The most recent hole may be equal to provided position. The next + //! hole will be 200000000 if all holes of the current rotation are in + //! the past. + + /*! @param pos angular position + @param last most recent index hole + @param next next index hole + */ + void find_index_hole(uint32_t pos, uint32_t &last, uint32_t &next) const; /*! @param track @@ -608,7 +647,7 @@ public: private: int tracks, heads; - uint32_t form_factor, variant; + uint32_t form_factor, variant, sectoring; struct track_info { @@ -621,6 +660,14 @@ private: // track number multiplied by 4 then head // last array size may be bigger than actual track size std::vector<std::vector<track_info> > track_array; + + // Additional index holes in increasing order. Entries are absolute + // positions of index holes in the same units as cell_data. The + // positions are the start of the hole, not the center of the hole. The + // hole at angular position 0 is implicit, so an empty list encodes a + // regular soft-sectored disk. Additional holes are found on + // hard-sectored disks. + std::vector<uint32_t> index_array; }; #endif // MAME_FORMATS_FLOPIMG_H diff --git a/src/lib/formats/flopimg_legacy.cpp b/src/lib/formats/flopimg_legacy.cpp index 5b8aee0a72b..c209b7cab58 100644 --- a/src/lib/formats/flopimg_legacy.cpp +++ b/src/lib/formats/flopimg_legacy.cpp @@ -349,16 +349,14 @@ util::random_read_write &floppy_get_io(floppy_image_legacy *floppy) void floppy_image_read(floppy_image_legacy *floppy, void *buffer, uint64_t offset, size_t length) { - size_t actual; - floppy->io->read_at(offset, buffer, length, actual); + /*auto const [err, actual] =*/ read_at(*floppy->io, offset, buffer, length); // FIXME: check for errors and premature EOF } void floppy_image_write(floppy_image_legacy *floppy, const void *buffer, uint64_t offset, size_t length) { - size_t actual; - floppy->io->write_at(offset, buffer, length, actual); + /*auto const [err, actual] =*/ write_at(*floppy->io, offset, buffer, length); // FIXME: check for errors } @@ -371,8 +369,7 @@ void floppy_image_write_filler(floppy_image_legacy *floppy, uint8_t filler, uint while (length) { size_t const block = std::min(sizeof(buffer), length); - size_t actual; - floppy->io->write_at(offset, buffer, block, actual); + /*auto const [err, actual] =*/ write_at(*floppy->io, offset, buffer, block); // FIXME: check for errors offset += block; length -= block; } diff --git a/src/lib/formats/fm7_cas.cpp b/src/lib/formats/fm7_cas.cpp index 54a5095547a..25953627361 100644 --- a/src/lib/formats/fm7_cas.cpp +++ b/src/lib/formats/fm7_cas.cpp @@ -72,7 +72,7 @@ static int fm7_cas_to_wav_size (const uint8_t *casdata, int caslen) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int fm7_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int fm7_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return fm7_handle_t77(buffer,bytes); } diff --git a/src/lib/formats/fmsx_cas.cpp b/src/lib/formats/fmsx_cas.cpp index b6642568b55..c7969b28eca 100644 --- a/src/lib/formats/fmsx_cas.cpp +++ b/src/lib/formats/fmsx_cas.cpp @@ -49,7 +49,7 @@ static int fmsx_cas_to_wav_size (const uint8_t *casdata, int caslen) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int fmsx_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int fmsx_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { int cas_pos, bit, state = 1, samples_pos, size, n, i, p; diff --git a/src/lib/formats/fs_cbmdos.cpp b/src/lib/formats/fs_cbmdos.cpp index 51d1369b04f..44c810a04a6 100644 --- a/src/lib/formats/fs_cbmdos.cpp +++ b/src/lib/formats/fs_cbmdos.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nathan Woods +// copyright-holders:Nathan Woods, Wilbert Pol /*************************************************************************** fs_cbmdos.cpp @@ -8,21 +8,30 @@ http://fileformats.archiveteam.org/wiki/CBMFS +Current limitations: +- Writing is limited to the first 35 tracks. +- Determine or select the file type. Currently defaulting to PRG; 0 byte files + will be assigned file type DEL. + ***************************************************************************/ #include "fs_cbmdos.h" + #include "d64_dsk.h" #include "fsblk.h" #include "corestr.h" +#include "multibyte.h" #include "strformat.h" #include <array> #include <optional> +#include <regex> #include <set> #include <string_view> #include <tuple> + namespace fs { const cbmdos_image CBMDOS; }; @@ -33,6 +42,8 @@ namespace { class impl : public filesystem_t { public: + static constexpr u8 SECTOR_DIRECTORY_COUNT = 8; + struct cbmdos_dirent { u8 m_next_directory_track; @@ -55,30 +66,74 @@ public: block_iterator(const impl &fs, u8 first_track, u8 first_sector); bool next(); const void *data() const; - const std::array<cbmdos_dirent, 4> &dirent_data() const; + const std::array<cbmdos_dirent, SECTOR_DIRECTORY_COUNT> &dirent_data() const; u8 size() const; + u8 track() const { return m_track; } + u8 sector() const { return m_sector; } private: const impl & m_fs; - fsblk_t::block_t m_block; + fsblk_t::block_t::ptr m_block; std::set<std::tuple<u8, u8>> m_visited_set; u8 m_track; u8 m_sector; + u8 m_next_track; + u8 m_next_sector; }; impl(fsblk_t &blockdev); virtual ~impl() = default; virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; private: - fsblk_t::block_t read_sector(int track, int sector) const; + static constexpr u32 BLOCK_SIZE = 256; + static constexpr u8 DIRECTORY_ENTRY_SIZE = 0x20; + static constexpr u8 FILE_TYPE_DEL = 0x80; + static constexpr u8 FILE_TYPE_SEQ = 0x81; + static constexpr u8 FILE_TYPE_PRG = 0x82; + static constexpr u8 FILE_TYPE_USR = 0x83; + static constexpr u8 FILE_TYPE_REL = 0x84; + static constexpr u8 TRACK_VARIANTS = 5; + static constexpr u8 MAX_SECTORS = 21; + static constexpr u8 MAX_TRACKS = 40; + static constexpr u8 DIRECTORY_TRACK = 18; + static constexpr u8 BAM_SECTOR = 0; + static constexpr u8 FIRST_DIRECTORY_SECTOR = 1; + static constexpr u8 SECTOR_DATA_BYTES = 254; + static constexpr u8 OFFSET_FILE_TYPE = 0x02; + static constexpr u8 OFFSET_FILE_FIRST_TRACK = 0x03; + static constexpr u8 OFFSET_FILE_FIRST_SECTOR = 0x04; + static constexpr u8 OFFSET_FILE_NAME = 0x05; + static constexpr u8 OFFSET_SECTOR_COUNT = 0x1e; + static constexpr u8 OFFSET_CHAIN_TRACK = 0x00; + static constexpr u8 OFFSET_CHAIN_SECTOR = 0x01; + static constexpr u8 CHAIN_END = 0x00; + + static const struct smap + { + u8 first_track; + u8 last_track; + int sector[MAX_SECTORS]; + } s_track_sector_map[TRACK_VARIANTS]; + static const u8 s_data_track_order[MAX_TRACKS - 1]; + u8 m_max_track; + + fsblk_t::block_t::ptr read_sector(int track, int sector) const; std::optional<cbmdos_dirent> dirent_from_path(const std::vector<std::string> &path) const; - void iterate_directory_entries(const std::function<bool(const cbmdos_dirent &dirent)> &callback) const; + void iterate_directory_entries(const std::function<bool(u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent)> &callback) const; + void iterate_all_directory_entries(const std::function<bool(u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent)> &callback) const; meta_data metadata_from_dirent(const cbmdos_dirent &dirent) const; + bool is_valid_filename(const std::string &filename) const; + std::pair<std::error_condition, u8> claim_track_sector(u8 track) const; + std::tuple<std::error_condition, u8, u8> claim_sector() const; + std::error_condition free_sector(u8 track, u8 sector) const; + u8 determine_file_type(const std::vector<u8> &data) const; }; // methods @@ -145,7 +200,7 @@ bool fs::cbmdos_image::can_read() const bool fs::cbmdos_image::can_write() const { - return false; + return true; } @@ -223,8 +278,22 @@ std::string_view strtrimright_cbm(const char (&str)[N]) // impl ctor //------------------------------------------------- +const u8 impl::s_data_track_order[MAX_TRACKS - 1] = { + 17, 19, 16, 20, 15, 21, 14, 22, 13, 23, 12, 24, 11, 25, 10, 26, 9, 27, 8, 28, 7, 29, 6, 30, 5, 31, 4, 32, 3, 33, 2, 34, 1, 35, 36, 37, 38, 39, 40 +}; + +const impl::smap impl::s_track_sector_map[TRACK_VARIANTS] = { + { 1, 17, { 0, 11, 1, 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10 } }, + { 18, 18, { 0, 1, 4, 7, 10, 13, 16, 2, 5, 8, 11, 14, 17, 3, 6, 9, 12, 15, 18, -1, -1 } }, + { 19, 24, { 0, 10, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, -1, -1 } }, + { 25, 30, { 0, 9, 1, 10, 2, 11, 3, 12, 4, 13, 5, 14, 6, 15, 7, 16, 8, 17, -1, -1, -1 } }, + { 31, 40, { 0, 9, 1, 10, 2, 11, 3, 12, 4, 13, 5, 14, 6, 15, 7, 16, 8, -1, -1, -1, -1 } } +}; + + impl::impl(fsblk_t &blockdev) - : filesystem_t(blockdev, 256) + : filesystem_t(blockdev, BLOCK_SIZE) + , m_max_track(35) { } @@ -235,8 +304,8 @@ impl::impl(fsblk_t &blockdev) meta_data impl::volume_metadata() { - auto bam_block = read_sector(18, 0); - std::string_view disk_name = std::string_view((const char *) bam_block.rodata() + 0x90, 16); + auto bam_block = read_sector(DIRECTORY_TRACK, BAM_SECTOR); + std::string_view disk_name = bam_block->rstr(0x90, 16); meta_data results; results.set(meta_name::name, strtrimright_cbm(disk_name)); @@ -248,13 +317,13 @@ meta_data impl::volume_metadata() // impl::metadata //------------------------------------------------- -std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> impl::metadata(const std::vector<std::string> &path) { std::optional<cbmdos_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, metadata_from_dirent(*dirent)); + return std::make_pair(std::error_condition(), metadata_from_dirent(*dirent)); } @@ -262,16 +331,16 @@ std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) // impl::directory_contents //------------------------------------------------- -std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) { std::vector<dir_entry> results; - auto callback = [this, &results](const cbmdos_dirent &ent) + auto callback = [this, &results](u8 track, u8 sector, u8 file_index, const cbmdos_dirent &ent) { results.emplace_back(dir_entry_type::file, metadata_from_dirent(ent)); return false; }; iterate_directory_entries(callback); - return std::make_pair(ERR_OK, std::move(results)); + return std::make_pair(std::error_condition(), std::move(results)); } @@ -279,12 +348,12 @@ std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vec // impl::file_read //------------------------------------------------- -std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) { // find the file std::optional<cbmdos_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); // and get the data std::vector<u8> result; @@ -292,7 +361,263 @@ std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> while (iter.next()) result.insert(result.end(), (const u8 *)iter.data(), (const u8 *)iter.data() + iter.size()); - return std::make_pair(ERR_OK, std::move(result)); + return std::make_pair(std::error_condition(), std::move(result)); +} + + +std::error_condition impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +{ + std::string filename = meta.get_string(meta_name::name, ""); + if (!is_valid_filename(filename)) + return error::invalid_name; + + std::optional<cbmdos_dirent> result; + u8 track = 0; + u8 sector = 0; + u8 file_index = 0; + auto callback = [&result, &track, §or, &file_index](u8 t, u8 s, u8 i, const cbmdos_dirent &dirent) + { + bool found = dirent.m_file_type == 0x00; + if (found) + { + result = dirent; + track = t; + sector = s; + file_index = i; + } + return found; + }; + iterate_all_directory_entries(callback); + + if (!result) + { + // Claim a next directory sector + auto const [err, new_sector] = claim_track_sector(DIRECTORY_TRACK); + if (err) + return err; + auto new_block = read_sector(DIRECTORY_TRACK, new_sector); + for (int i = 2; i < BLOCK_SIZE; i++) + new_block->w8(i, 0); + // Find last directory sector + u8 last_sector = 0; + block_iterator iter(*this, DIRECTORY_TRACK, FIRST_DIRECTORY_SECTOR); + while (iter.next()) + last_sector = iter.sector(); + // Update chain on last directory sector + auto last_dir_block = read_sector(DIRECTORY_TRACK, last_sector); + last_dir_block->w8(OFFSET_CHAIN_TRACK, DIRECTORY_TRACK); + last_dir_block->w8(OFFSET_CHAIN_SECTOR, new_sector); + track = DIRECTORY_TRACK; + sector = new_sector; + } + + auto const [err, file_track, file_sector] = claim_sector(); + if (err) + return err; + + // Create the file + auto dirblk = read_sector(track, sector); + u32 offset = file_index * DIRECTORY_ENTRY_SIZE; + for (int i = 0; i < DIRECTORY_ENTRY_SIZE; i++) + dirblk->w8(offset + i, (i >= 5 && i < 5 + 16) ? 0xa0 : 0x00); + dirblk->w8(offset + OFFSET_FILE_TYPE, FILE_TYPE_PRG); + dirblk->w8(offset + OFFSET_FILE_FIRST_TRACK, file_track); + dirblk->w8(offset + OFFSET_FILE_FIRST_SECTOR, file_sector); + dirblk->wstr(offset + OFFSET_FILE_NAME, filename); + // TODO set first side sector block track (rel file) + // TODO set first side sector block sector (rel file) + // TODO set rel file record length + // sector count will be set while writing the data + + return std::error_condition(); +} + + +std::error_condition impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +{ + if (path.size() != 1) + return error::not_found; + std::string_view path_part = path[0]; + + std::optional<cbmdos_dirent> result; + u8 dir_track = 0; + u8 dir_sector = 0; + u8 dir_file_index = 0; + auto const callback = [&result, &dir_track, &dir_sector, &dir_file_index, path_part] (u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent) + { + bool found = strtrimright_cbm(dirent.m_file_name) == path_part; + if (found) + { + dir_track = track; + dir_sector = sector; + dir_file_index = file_index; + result = dirent; + } + return found; + }; + iterate_directory_entries(callback); + + if (!result) + return error::not_found; + + u8 data_track = result->m_file_first_track; + u8 data_sector = result->m_file_first_sector; + + const size_t data_length = data.size(); + size_t offset = 0; + u32 sector_count = 0; + while (offset < data_length) + { + auto datablk = read_sector(data_track, data_sector); + u8 bytes = (data_length - offset) > SECTOR_DATA_BYTES ? SECTOR_DATA_BYTES : data_length - offset; + datablk->write(2, data.data() + offset, bytes); + offset += SECTOR_DATA_BYTES; + sector_count++; + if (datablk->r8(OFFSET_CHAIN_TRACK) == CHAIN_END) + { + if (offset < data_length) + { + auto [err, next_track, next_sector] = claim_sector(); + if (err) + return err; + datablk->w8(OFFSET_CHAIN_TRACK, next_track); + datablk->w8(OFFSET_CHAIN_SECTOR, next_sector); + data_track = next_track; + data_sector = next_sector; + } + } + else + { + if (offset < data_length) + { + data_track = datablk->r8(OFFSET_CHAIN_TRACK); + data_sector = datablk->r8(OFFSET_CHAIN_SECTOR); + } + else + { + // Free the rest of the chain + u8 track_to_free = datablk->r8(OFFSET_CHAIN_TRACK); + u8 sector_to_free = datablk->r8(OFFSET_CHAIN_SECTOR); + + while (track_to_free != CHAIN_END) + { + std::error_condition const err = free_sector(track_to_free, sector_to_free); + if (err) + return err; + datablk = read_sector(track_to_free, sector_to_free); + track_to_free = datablk->r8(OFFSET_CHAIN_TRACK); + sector_to_free = datablk->r8(OFFSET_CHAIN_SECTOR); + } + } + } + if (offset >= data_length) + { + datablk->w8(OFFSET_CHAIN_TRACK, CHAIN_END); + datablk->w8(OFFSET_CHAIN_SECTOR, bytes + 1); + } + } + + // Write sector count and file type to directory entry + auto dirblk = read_sector(dir_track, dir_sector); + u8 file_type = determine_file_type(data); + if (file_type == FILE_TYPE_DEL) + { + // Free sector, update first file sector to 00 + u8 file_track = dirblk->r8(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_FILE_FIRST_TRACK); + u8 file_sector = dirblk->r8(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_FILE_FIRST_SECTOR); + std::error_condition err = free_sector(file_track, file_sector); + if (err) + return err; + dirblk->w8(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_FILE_FIRST_TRACK, 0); + dirblk->w8(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_FILE_FIRST_SECTOR, 0); + sector_count = 0; + } + dirblk->w8(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_FILE_TYPE, file_type); + dirblk->w16l(DIRECTORY_ENTRY_SIZE * dir_file_index + OFFSET_SECTOR_COUNT, sector_count); + + return std::error_condition(); +} + + +u8 impl::determine_file_type(const std::vector<u8> &data) const +{ + // TODO: Determine/set the actual file type, defaulting to PRG for now. + const size_t data_length = data.size(); + if (data_length == 0) + return FILE_TYPE_DEL; + return FILE_TYPE_PRG; +} + + +bool impl::is_valid_filename(const std::string &filename) const +{ + // We only support a subset of the character set supported by Commodore for filenames. + std::regex filename_regex("[A-Z0-9!\"#\\$%&'\\(\\)*+,-./:;<=>?]{1,16}"); + return std::regex_match(filename, filename_regex); +} + + +std::pair<std::error_condition, u8> impl::claim_track_sector(u8 track) const +{ + if (track == 0 || track > m_max_track) + return std::make_pair(error::invalid_block, 0); + + u8 map_index; + for (map_index = 0; map_index < TRACK_VARIANTS && !(s_track_sector_map[map_index].first_track <= track && track <= s_track_sector_map[map_index].last_track) ; map_index++); + if (map_index >= TRACK_VARIANTS) + return std::make_pair(error::invalid_block, 0); + + auto bamblk = read_sector(DIRECTORY_TRACK, BAM_SECTOR); + u8 free_count = bamblk->r8(4 * track); + u32 free_bitmap = bamblk->r24l(4 * track + 1); + + for (int s = 0; s < MAX_SECTORS; s++) + { + int sector = s_track_sector_map[map_index].sector[s]; + if (sector >= 0 && free_count > 0 && util::BIT(free_bitmap, sector)) + { + free_bitmap &= ~(1 << sector); + free_count--; + bamblk->w8(4 * track, free_count); + bamblk->w24l(4 * track + 1, free_bitmap); + // Write chain end marker in new sector + auto claimedlk = read_sector(track, sector); + claimedlk->w8(OFFSET_CHAIN_TRACK, CHAIN_END); + claimedlk->w8(OFFSET_CHAIN_SECTOR, 0xff); + return std::make_pair(std::error_condition(), sector); + } + } + return std::make_pair(error::no_space, 0); +} + + +std::tuple<std::error_condition, u8, u8> impl::claim_sector() const +{ + for (int track = 0; track < m_max_track - 1; track++) + { + auto const [err, sector] = claim_track_sector(s_data_track_order[track]); + if (!err) + return std::make_tuple(std::error_condition(), s_data_track_order[track], sector); + if (err != error::no_space) + return std::make_tuple(err, 0, 0); + } + return std::make_tuple(error::no_space, 0, 0); +} + + +std::error_condition impl::free_sector(u8 track, u8 sector) const +{ + if (track == 0 || track > m_max_track) + return error::invalid_block; + + auto bamblk = read_sector(DIRECTORY_TRACK, BAM_SECTOR); + u8 free_count = bamblk->r8(4 * track); + u32 free_bitmap = bamblk->r24l(4 * track + 1); + free_bitmap |= (1 << sector); + free_count++; + bamblk->w8(4 * track, free_count); + bamblk->w24l(4 * track + 1, free_bitmap); + return std::error_condition(); } @@ -300,7 +625,7 @@ std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> // impl::read_sector //------------------------------------------------- -fsblk_t::block_t impl::read_sector(int track, int sector) const +fsblk_t::block_t::ptr impl::read_sector(int track, int sector) const { // CBM thinks in terms of tracks/sectors, but we have a block device abstraction u32 block = 0; @@ -320,13 +645,13 @@ fsblk_t::block_t impl::read_sector(int track, int sector) const std::optional<impl::cbmdos_dirent> impl::dirent_from_path(const std::vector<std::string> &path) const { if (path.size() != 1) - return { }; + return std::nullopt; std::string_view path_part = path[0]; std::optional<cbmdos_dirent> result; - auto callback = [&result, path_part](const cbmdos_dirent &dirent) + auto const callback = [&result, path_part] (u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent) { - bool found = strtrimright_cbm(dirent.m_file_name) == path_part; + bool const found = strtrimright_cbm(dirent.m_file_name) == path_part; if (found) result = dirent; return found; @@ -340,22 +665,38 @@ std::optional<impl::cbmdos_dirent> impl::dirent_from_path(const std::vector<std: // impl::iterate_directory_entries //------------------------------------------------- -void impl::iterate_directory_entries(const std::function<bool(const cbmdos_dirent &dirent)> &callback) const +void impl::iterate_directory_entries(const std::function<bool(u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent)> &callback) const { - block_iterator iter(*this, 18, 1); + block_iterator iter(*this, DIRECTORY_TRACK, FIRST_DIRECTORY_SECTOR); while (iter.next()) { - for (const cbmdos_dirent &ent : iter.dirent_data()) + auto entries = iter.dirent_data(); + + for (int file_index = 0; file_index < SECTOR_DIRECTORY_COUNT; file_index++) { - if (ent.m_file_type != 0x00) + if (entries[file_index].m_file_type != 0x00) { - if (callback(ent)) + if (callback(iter.track(), iter.sector(), file_index, entries[file_index])) return; } } } } +void impl::iterate_all_directory_entries(const std::function<bool(u8 track, u8 sector, u8 file_index, const cbmdos_dirent &dirent)> &callback) const +{ + block_iterator iter(*this, DIRECTORY_TRACK, FIRST_DIRECTORY_SECTOR); + while (iter.next()) + { + auto entries = iter.dirent_data(); + + for (int file_index = 0; file_index < SECTOR_DIRECTORY_COUNT; file_index++) + { + if (callback(iter.track(), iter.sector(), file_index, entries[file_index])) + return; + } + } +} //------------------------------------------------- // impl::metadata_from_dirent @@ -366,19 +707,19 @@ meta_data impl::metadata_from_dirent(const cbmdos_dirent &dirent) const std::string file_type; switch (dirent.m_file_type) { - case 0x80: + case FILE_TYPE_DEL: file_type = "DEL"; break; - case 0x81: + case FILE_TYPE_SEQ: file_type = "SEQ"; break; - case 0x82: + case FILE_TYPE_PRG: file_type = "PRG"; break; - case 0x83: + case FILE_TYPE_USR: file_type = "USR"; break; - case 0x84: + case FILE_TYPE_REL: file_type = "REL"; break; default: @@ -409,6 +750,8 @@ impl::block_iterator::block_iterator(const impl &fs, u8 first_track, u8 first_se : m_fs(fs) , m_track(first_track) , m_sector(first_sector) + , m_next_track(first_track) + , m_next_sector(first_sector) { } @@ -420,19 +763,21 @@ impl::block_iterator::block_iterator(const impl &fs, u8 first_track, u8 first_se bool impl::block_iterator::next() { bool result; - if (m_track != 0x00) + m_track = m_next_track; + m_sector = m_next_sector; + if (m_track != CHAIN_END) { // check for the degenerate scenario where we have a cycle (this should not happen // on a non-corrupt disk) - auto visited_tuple = std::make_tuple(m_track, m_sector); + auto visited_tuple = std::make_tuple(m_next_track, m_next_sector); if (m_visited_set.find(visited_tuple) != m_visited_set.end()) return false; m_visited_set.insert(visited_tuple); // with that out of the way, proceed - m_block = m_fs.read_sector(m_track, m_sector); - m_track = m_block.r8(0); - m_sector = m_block.r8(1); + m_block = m_fs.read_sector(m_next_track, m_next_sector); + m_next_track = m_block->r8(OFFSET_CHAIN_TRACK); + m_next_sector = m_block->r8(OFFSET_CHAIN_SECTOR); result = true; } else @@ -450,7 +795,7 @@ bool impl::block_iterator::next() const void *impl::block_iterator::data() const { - return m_block.rodata() + 2; + return m_block->rodata() + 2; } @@ -458,9 +803,9 @@ const void *impl::block_iterator::data() const // impl::block_iterator::dirent_data //------------------------------------------------- -const std::array<impl::cbmdos_dirent, 4> &impl::block_iterator::dirent_data() const +const std::array<impl::cbmdos_dirent, impl::SECTOR_DIRECTORY_COUNT> &impl::block_iterator::dirent_data() const { - return *reinterpret_cast<const std::array<impl::cbmdos_dirent, 4> *>(m_block.rodata()); + return *reinterpret_cast<const std::array<impl::cbmdos_dirent, SECTOR_DIRECTORY_COUNT> *>(m_block->rodata()); } @@ -470,7 +815,7 @@ const std::array<impl::cbmdos_dirent, 4> &impl::block_iterator::dirent_data() co u8 impl::block_iterator::size() const { - return m_track != 0x00 ? 254 : m_sector - 1; + return (m_track != CHAIN_END) ? SECTOR_DATA_BYTES : (m_sector - 1); } } // anonymous namespace diff --git a/src/lib/formats/fs_coco_os9.cpp b/src/lib/formats/fs_coco_os9.cpp index f8a14c7acdd..8e9d9e8c8d0 100644 --- a/src/lib/formats/fs_coco_os9.cpp +++ b/src/lib/formats/fs_coco_os9.cpp @@ -39,23 +39,23 @@ public: class volume_header { public: - volume_header(fsblk_t::block_t &&block); + volume_header(fsblk_t::block_t::ptr &&block); volume_header(const volume_header &) = delete; volume_header(volume_header &&) = default; - u32 total_sectors() const { return m_block.r24b(0); } - u8 track_size_in_sectors() const { return m_block.r8(3); } - u16 allocation_bitmap_bytes() const { return m_block.r16b(4); } - u16 cluster_size() const { return m_block.r16b(6); } - u32 root_dir_lsn() const { return m_block.r24b(8); } - u16 owner_id() const { return m_block.r16b(11); } - u16 disk_id() const { return m_block.r16b(14); } - u8 format_flags() const { return m_block.r8(16); } - u16 sectors_per_track() const { return m_block.r16b(17); } - u32 bootstrap_lsn() const { return m_block.r24b(21); } - u16 bootstrap_size() const { return m_block.r16b(24); } - util::arbitrary_datetime creation_date() const { return from_os9_date(m_block.r24b(26), m_block.r16b(29)); } - u16 sector_size() const { u16 result = m_block.r16b(104); return result != 0 ? result : 256; } + u32 total_sectors() const { return m_block->r24b(0); } + u8 track_size_in_sectors() const { return m_block->r8(3); } + u16 allocation_bitmap_bytes() const { return m_block->r16b(4); } + u16 cluster_size() const { return m_block->r16b(6); } + u32 root_dir_lsn() const { return m_block->r24b(8); } + u16 owner_id() const { return m_block->r16b(11); } + u16 disk_id() const { return m_block->r16b(14); } + u8 format_flags() const { return m_block->r8(16); } + u16 sectors_per_track() const { return m_block->r16b(17); } + u32 bootstrap_lsn() const { return m_block->r24b(21); } + u16 bootstrap_size() const { return m_block->r16b(24); } + util::arbitrary_datetime creation_date() const { return from_os9_date(m_block->r24b(26), m_block->r16b(29)); } + u16 sector_size() const { u16 result = m_block->r16b(104); return result != 0 ? result : 256; } u8 sides() const { return (format_flags() & 0x01) ? 2 : 1; } bool double_density() const { return (format_flags() & 0x02) != 0; } bool double_track() const { return (format_flags() & 0x04) != 0; } @@ -65,7 +65,7 @@ public: std::string name() const; private: - fsblk_t::block_t m_block; + fsblk_t::block_t::ptr m_block; }; @@ -74,17 +74,17 @@ public: class file_header { public: - file_header(fsblk_t::block_t &&block, std::string &&filename); + file_header(fsblk_t::block_t::ptr &&block, std::string &&filename); file_header(const file_header &) = delete; file_header(file_header &&) = default; file_header &operator=(const file_header &) = delete; file_header &operator=(file_header &&) = default; - u8 attributes() const { return m_block.r8(0); } - u16 owner_id() const { return m_block.r16b(1); } - u8 link_count() const { return m_block.r8(8); } - u32 file_size() const { return m_block.r32b(9); } + u8 attributes() const { return m_block->r8(0); } + u16 owner_id() const { return m_block->r16b(1); } + u8 link_count() const { return m_block->r8(8); } + u32 file_size() const { return m_block->r32b(9); } util::arbitrary_datetime creation_date() const; bool is_directory() const { return (attributes() & 0x80) != 0; } bool is_non_sharable() const { return (attributes() & 0x40) != 0; } @@ -100,8 +100,8 @@ public: void get_sector_map_entry(int entry_number, u32 &start_lsn, u16 &count) const; private: - fsblk_t::block_t m_block; - std::string m_filename; + fsblk_t::block_t::ptr m_block; + std::string m_filename; }; // ctor/dtor @@ -109,10 +109,10 @@ public: virtual ~coco_os9_impl() = default; virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t format(const meta_data &meta) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition format(const meta_data &meta) override; std::optional<file_header> find(const std::vector<std::string> &path, std::optional<dir_entry_type> expected_entry_type) const; void iterate_directory_entries(const file_header &header, const std::function<bool(std::string &&, u32)> callback) const; @@ -301,14 +301,14 @@ meta_data coco_os9_impl::volume_metadata() // coco_os9_impl::metadata //------------------------------------------------- -std::pair<err_t, meta_data> coco_os9_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> coco_os9_impl::metadata(const std::vector<std::string> &path) { // look up the path std::optional<file_header> header = find(path, { }); if (!header) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, header->metadata()); + return std::make_pair(std::error_condition(), header->metadata()); } @@ -316,12 +316,12 @@ std::pair<err_t, meta_data> coco_os9_impl::metadata(const std::vector<std::strin // coco_os9_impl::directory_contents //------------------------------------------------- -std::pair<err_t, std::vector<dir_entry>> coco_os9_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> coco_os9_impl::directory_contents(const std::vector<std::string> &path) { // look up the path std::optional<file_header> header = find(path, dir_entry_type::dir); if (!header) - return std::make_pair(ERR_NOT_FOUND, std::vector<dir_entry>()); + return std::make_pair(error::not_found, std::vector<dir_entry>()); // iterate through the directory std::vector<dir_entry> results; @@ -337,7 +337,7 @@ std::pair<err_t, std::vector<dir_entry>> coco_os9_impl::directory_contents(const iterate_directory_entries(*header, callback); // and we're done - return std::make_pair(ERR_OK, std::move(results)); + return std::make_pair(std::error_condition(), std::move(results)); } @@ -345,15 +345,15 @@ std::pair<err_t, std::vector<dir_entry>> coco_os9_impl::directory_contents(const // coco_os9_impl::file_read //------------------------------------------------- -std::pair<err_t, std::vector<u8>> coco_os9_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> coco_os9_impl::file_read(const std::vector<std::string> &path) { // look up the path std::optional<file_header> header = find(path, dir_entry_type::file); if (!header) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); std::vector<u8> data = read_file_data(*header); - return std::make_pair(ERR_OK, std::move(data)); + return std::make_pair(std::error_condition(), std::move(data)); } @@ -361,10 +361,10 @@ std::pair<err_t, std::vector<u8>> coco_os9_impl::file_read(const std::vector<std // coco_os9_impl::format //------------------------------------------------- -err_t coco_os9_impl::format(const meta_data &meta) +std::error_condition coco_os9_impl::format(const meta_data &meta) { // for some reason, the OS-9 world favored filling with 0xE5 - m_blockdev.fill(0xE5); + m_blockdev.fill_all(0xe5); // identify geometry info u8 sectors = 18; // TODO - we need a definitive technique to get the floppy geometry @@ -390,33 +390,33 @@ err_t coco_os9_impl::format(const meta_data &meta) // volume header auto volume_header = m_blockdev.get(0); - volume_header.fill(0x00); - volume_header.w24b(0, lsn_count); // DD.TOT - total secctors - volume_header.w8(3, sectors); // DD.TKS - track size in sectors - volume_header.w16b(4, (allocation_bitmap_bits + 7) / 8); // DD.MAP - allocation bitmap in bytes - volume_header.w16b(6, cluster_size); // DD.BIT - cluster size - volume_header.w24b(8, 1 + allocation_bitmap_lsns); // DD.DIR - root directory LSN - volume_header.w16b(11, owner_id); // DD.OWN - owner ID - volume_header.w8(13, attributes); // DD.ATT - Dattributes - volume_header.w16b(14, disk_id); // DD.DSK - disk ID - volume_header.w8(16, format_flags); // DD.FMT - format flags - volume_header.w16b(17, sectors); // DD.SPT - sectors per track - volume_header.w24b(26, creation_os9date); // DD.DAT - date of creation - volume_header.w16b(29, creation_os9time); // DD.DAT - time of creation - volume_header.wstr(31, to_os9_string(volume_title, 32)); // DD.NAM - title - volume_header.w16b(103, sector_bytes / 256); // sector bytes + volume_header->fill(0x00); + volume_header->w24b(0, lsn_count); // DD.TOT - total secctors + volume_header->w8(3, sectors); // DD.TKS - track size in sectors + volume_header->w16b(4, (allocation_bitmap_bits + 7) / 8); // DD.MAP - allocation bitmap in bytes + volume_header->w16b(6, cluster_size); // DD.BIT - cluster size + volume_header->w24b(8, 1 + allocation_bitmap_lsns); // DD.DIR - root directory LSN + volume_header->w16b(11, owner_id); // DD.OWN - owner ID + volume_header->w8(13, attributes); // DD.ATT - Dattributes + volume_header->w16b(14, disk_id); // DD.DSK - disk ID + volume_header->w8(16, format_flags); // DD.FMT - format flags + volume_header->w16b(17, sectors); // DD.SPT - sectors per track + volume_header->w24b(26, creation_os9date); // DD.DAT - date of creation + volume_header->w16b(29, creation_os9time); // DD.DAT - time of creation + volume_header->wstr(31, to_os9_string(volume_title, 32)); // DD.NAM - title + volume_header->w16b(103, sector_bytes / 256); // sector bytes // path descriptor options - volume_header.w8(0x3f + 0x00, 1); // device class - volume_header.w8(0x3f + 0x01, 1); // drive number - volume_header.w8(0x3f + 0x03, 0x20); // device type - volume_header.w8(0x3f + 0x04, 1); // density capability - volume_header.w16b(0x3f + 0x05, tracks); // number of tracks - volume_header.w8(0x3f + 0x07, heads); // number of sides - volume_header.w16b(0x3f + 0x09, sectors); // sectors per track - volume_header.w16b(0x3f + 0x0b, sectors); // sectors on track zero - volume_header.w8(0x3f + 0x0d, 3); // sector interleave factor - volume_header.w8(0x3f + 0x0e, 8); // default sectors per allocation + volume_header->w8(0x3f + 0x00, 1); // device class + volume_header->w8(0x3f + 0x01, 1); // drive number + volume_header->w8(0x3f + 0x03, 0x20); // device type + volume_header->w8(0x3f + 0x04, 1); // density capability + volume_header->w16b(0x3f + 0x05, tracks); // number of tracks + volume_header->w8(0x3f + 0x07, heads); // number of sides + volume_header->w16b(0x3f + 0x09, sectors); // sectors per track + volume_header->w16b(0x3f + 0x0b, sectors); // sectors on track zero + volume_header->w8(0x3f + 0x0d, 3); // sector interleave factor + volume_header->w8(0x3f + 0x0e, 8); // default sectors per allocation // allocation bitmap u32 total_allocated_sectors = 1 + allocation_bitmap_lsns + 1 + 8; @@ -428,7 +428,7 @@ err_t coco_os9_impl::format(const meta_data &meta) { u32 pos = (i * sector_bytes + j) * 8; if (pos + 8 < total_allocated_sectors) - abblk_bytes[j] = 0xFF; + abblk_bytes[j] = 0xff; else if (pos >= total_allocated_sectors) abblk_bytes[j] = 0x00; else @@ -436,35 +436,35 @@ err_t coco_os9_impl::format(const meta_data &meta) } auto abblk = m_blockdev.get(1 + i); - abblk.copy(0, abblk_bytes.data(), sector_bytes); + abblk->write(0, abblk_bytes.data(), sector_bytes); } // root directory header auto roothdr_blk = m_blockdev.get(1 + allocation_bitmap_lsns); - roothdr_blk.fill(0x00); - roothdr_blk.w8(0x00, 0xBF); - roothdr_blk.w8(0x01, 0x00); - roothdr_blk.w8(0x02, 0x00); - roothdr_blk.w24b(0x03, creation_os9date); - roothdr_blk.w16b(0x06, creation_os9time); - roothdr_blk.w8(0x08, 0x01); - roothdr_blk.w8(0x09, 0x00); - roothdr_blk.w8(0x0A, 0x00); - roothdr_blk.w8(0x0B, 0x00); - roothdr_blk.w8(0x0C, 0x40); - roothdr_blk.w24b(0x0D, creation_os9date); - roothdr_blk.w24b(0x10, 1 + allocation_bitmap_lsns + 1); - roothdr_blk.w16b(0x13, 8); + roothdr_blk->fill(0x00); + roothdr_blk->w8(0x00, 0xbf); + roothdr_blk->w8(0x01, 0x00); + roothdr_blk->w8(0x02, 0x00); + roothdr_blk->w24b(0x03, creation_os9date); + roothdr_blk->w16b(0x06, creation_os9time); + roothdr_blk->w8(0x08, 0x01); + roothdr_blk->w8(0x09, 0x00); + roothdr_blk->w8(0x0a, 0x00); + roothdr_blk->w8(0x0b, 0x00); + roothdr_blk->w8(0x0c, 0x40); + roothdr_blk->w24b(0x0d, creation_os9date); + roothdr_blk->w24b(0x10, 1 + allocation_bitmap_lsns + 1); + roothdr_blk->w16b(0x13, 8); // root directory data auto rootdata_blk = m_blockdev.get(1 + allocation_bitmap_lsns + 1); - rootdata_blk.fill(0x00); - rootdata_blk.w8(0x00, 0x2E); - rootdata_blk.w8(0x01, 0xAE); - rootdata_blk.w8(0x1F, 1 + allocation_bitmap_lsns); - rootdata_blk.w8(0x20, 0xAE); - rootdata_blk.w8(0x3F, 1 + allocation_bitmap_lsns); - return ERR_OK; + rootdata_blk->fill(0x00); + rootdata_blk->w8(0x00, 0x2e); + rootdata_blk->w8(0x01, 0xae); + rootdata_blk->w8(0x1f, 1 + allocation_bitmap_lsns); + rootdata_blk->w8(0x20, 0xae); + rootdata_blk->w8(0x3f, 1 + allocation_bitmap_lsns); + return std::error_condition(); } @@ -554,9 +554,9 @@ std::vector<u8> coco_os9_impl::read_file_data(const file_header &header) const for (u32 lsn = start_lsn; lsn < start_lsn + count; lsn++) { auto block = m_blockdev.get(lsn); - size_t block_size = std::min(std::min(u32(m_volume_header.sector_size()), block.size()), header.file_size() - u32(data.size())); + size_t block_size = std::min(std::min(u32(m_volume_header.sector_size()), block->size()), header.file_size() - u32(data.size())); for (auto i = 0; i < block_size; i++) - data.push_back(block.rodata()[i]); + data.push_back(block->rodata()[i]); } } return data; @@ -580,7 +580,7 @@ std::string coco_os9_impl::pick_os9_string(std::string_view raw_string) // and add the final character if we have to if (iter < raw_string.end() && *iter & 0x80) - result.append(1, *iter & 0x7F); + result.append(1, *iter & 0x7f); return result; } @@ -595,7 +595,7 @@ std::string coco_os9_impl::to_os9_string(std::string_view s, size_t length) std::string result(length, '\0'); for (auto i = 0; i < std::min(length, s.size()); i++) { - result[i] = (s[i] & 0x7F) + result[i] = (s[i] & 0x7f) | (i == s.size() ? 0x80 : 0x00); } return result; @@ -610,11 +610,11 @@ util::arbitrary_datetime coco_os9_impl::from_os9_date(u32 os9_date, u16 os9_time { util::arbitrary_datetime dt; memset(&dt, 0, sizeof(dt)); - dt.year = ((os9_date >> 16) & 0xFF) + 1900; - dt.month = (os9_date >> 8) & 0xFF; - dt.day_of_month = (os9_date >> 0) & 0xFF; - dt.hour = (os9_time >> 8) & 0xFF; - dt.minute = (os9_time >> 0) & 0xFF; + dt.year = ((os9_date >> 16) & 0xff) + 1900; + dt.month = (os9_date >> 8) & 0xff; + dt.day_of_month = (os9_date >> 0) & 0xff; + dt.hour = (os9_time >> 8) & 0xff; + dt.minute = (os9_time >> 0) & 0xff; return dt; } @@ -625,11 +625,11 @@ util::arbitrary_datetime coco_os9_impl::from_os9_date(u32 os9_date, u16 os9_time std::tuple<u32, u16> coco_os9_impl::to_os9_date(const util::arbitrary_datetime &datetime) { - u32 os9_date = ((datetime.year - 1900) & 0xFF) << 16 - | (datetime.month & 0xFF) << 8 - | (datetime.day_of_month & 0xFF) << 0; - u16 os9_time = (datetime.hour & 0xFF) << 8 - | (datetime.minute & 0xFF) << 0; + u32 os9_date = ((datetime.year - 1900) & 0xff) << 16 + | (datetime.month & 0xff) << 8 + | (datetime.day_of_month & 0xff) << 0; + u16 os9_time = (datetime.hour & 0xff) << 8 + | (datetime.minute & 0xff) << 0; return std::make_tuple(os9_date, os9_time); } @@ -664,7 +664,7 @@ bool coco_os9_impl::is_ignored_filename(std::string_view name) // volume_header ctor //------------------------------------------------- -coco_os9_impl::volume_header::volume_header(fsblk_t::block_t &&block) +coco_os9_impl::volume_header::volume_header(fsblk_t::block_t::ptr &&block) : m_block(std::move(block)) { } @@ -676,7 +676,7 @@ coco_os9_impl::volume_header::volume_header(fsblk_t::block_t &&block) std::string coco_os9_impl::volume_header::name() const { - std::string_view raw_name((const char *)&m_block.rodata()[31], 32); + std::string_view raw_name(m_block->rstr(31, 32)); return pick_os9_string(raw_name); } @@ -685,7 +685,7 @@ std::string coco_os9_impl::volume_header::name() const // file_header ctor //------------------------------------------------- -coco_os9_impl::file_header::file_header(fsblk_t::block_t &&block, std::string &&filename) +coco_os9_impl::file_header::file_header(fsblk_t::block_t::ptr &&block, std::string &&filename) : m_block(std::move(block)) , m_filename(std::move(filename)) { @@ -698,7 +698,7 @@ coco_os9_impl::file_header::file_header(fsblk_t::block_t &&block, std::string && util::arbitrary_datetime coco_os9_impl::file_header::creation_date() const { - return from_os9_date(m_block.r24b(13)); + return from_os9_date(m_block->r24b(13)); } @@ -735,7 +735,7 @@ meta_data coco_os9_impl::file_header::metadata() const int coco_os9_impl::file_header::get_sector_map_entry_count() const { - return (m_block.size() - 16) / 5; + return (m_block->size() - 16) / 5; } @@ -745,6 +745,6 @@ int coco_os9_impl::file_header::get_sector_map_entry_count() const void coco_os9_impl::file_header::get_sector_map_entry(int entry_number, u32 &start_lsn, u16 &count) const { - start_lsn = m_block.r24b(16 + (entry_number * 5) + 0); - count = m_block.r16b(16 + (entry_number * 5) + 3); + start_lsn = m_block->r24b(16 + (entry_number * 5) + 0); + count = m_block->r16b(16 + (entry_number * 5) + 3); } diff --git a/src/lib/formats/fs_coco_rsdos.cpp b/src/lib/formats/fs_coco_rsdos.cpp index 76b737d9011..0ce88cf01df 100644 --- a/src/lib/formats/fs_coco_rsdos.cpp +++ b/src/lib/formats/fs_coco_rsdos.cpp @@ -1,11 +1,14 @@ // license:BSD-3-Clause -// copyright-holders:Nathan Woods +// copyright-holders:Nathan Woods, Wilbert Pol /*************************************************************************** fs_coco_rsdos.cpp Management of CoCo "RS-DOS" floppy images +Limitation: +- The determination of the file type is very limited. + ***************************************************************************/ #include "fs_coco_rsdos.h" @@ -16,6 +19,7 @@ #include <bitset> #include <optional> +#include <regex> #include <string_view> using namespace fs; @@ -30,6 +34,8 @@ public: coco_rsdos_impl(fsblk_t &blockdev); virtual ~coco_rsdos_impl() = default; + static constexpr int SECTOR_DIRECTORY_ENTRY_COUNT = 8; + struct rsdos_dirent { char m_filename[11]; @@ -46,7 +52,7 @@ public: { rsdos_dirent m_dirent; u8 m_unused[16]; - } m_entries[8]; + } m_entries[SECTOR_DIRECTORY_ENTRY_COUNT]; }; class granule_iterator @@ -56,27 +62,54 @@ public: bool next(u8 &granule, u16 &byte_count); private: - fsblk_t::block_t m_granule_map; - std::optional<u8> m_current_granule; - u8 m_maximum_granules; - u16 m_last_sector_bytes; - std::bitset<256> m_visited_granules; + fsblk_t::block_t::ptr m_granule_map; + std::optional<u8> m_current_granule; + u8 m_maximum_granules; + u16 m_last_sector_bytes; + std::bitset<256> m_visited_granules; }; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t format(const meta_data &meta) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition format(const meta_data &meta) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; static bool validate_filename(std::string_view name); private: - fsblk_t::block_t read_sector(int track, int sector) const; + static constexpr u8 TRACK_GRANULE_COUNT = 2; + static constexpr u8 GRANULE_SECTOR_COUNT = 9; + static constexpr u8 TRACK_SECTOR_COUNT = TRACK_GRANULE_COUNT * GRANULE_SECTOR_COUNT; + static constexpr u8 DIRECTORY_TRACK = 17; + static constexpr u8 DIRECTORY_ENTRY_SIZE = 0x20; + static constexpr u8 FNAME_LENGTH = 11; + static constexpr u16 SECTOR_SIZE = 0x100; + static constexpr u8 OFFSET_FILE_TYPE = 0x0b; + static constexpr u8 OFFSET_ASCII_FLAG = 0x0c; + static constexpr u8 OFFSET_FIRST_GRANULE = 0x0d; + static constexpr u8 OFFSET_LAST_SECTOR_BYTES = 0x0e; + static constexpr u8 FILE_TYPE_BASIC = 0x00; + static constexpr u8 FILE_TYPE_BASIC_DATA = 0x01; + static constexpr u8 FILE_TYPE_MACHINE_CODE = 0x02; + static constexpr u8 FILE_TYPE_TEXT_EDITOR = 0x03; + static constexpr u8 FILE_LAST_GRANULE_INDICATOR = 0xc0; + + fsblk_t::block_t::ptr read_sector(int track, int sector) const; + fsblk_t::block_t::ptr read_granule_sector(u8 granule, u8 sector) const; u8 maximum_granules() const; std::optional<rsdos_dirent> dirent_from_path(const std::vector<std::string> &path); - void iterate_directory_entries(const std::function<bool(const rsdos_dirent &dirent)> &callback); + template <typename T> + void iterate_directory_entries(T &&callback); meta_data get_metadata_from_dirent(const rsdos_dirent &dirent); static std::string get_filename_from_dirent(const rsdos_dirent &dirent); + std::pair<std::error_condition, std::string> build_direntry_filename(const std::string &filename); + std::pair<std::error_condition, u8> claim_granule(); + void write_granule_map(u8 granule, u8 map_data); + u8 read_granule_map(u8 granule) const; + bool is_ascii(const std::vector<u8> &data) const; + u8 determine_file_type(const std::vector<u8> &data) const; }; } // anonymous namespace @@ -139,7 +172,7 @@ bool coco_rsdos_image::can_read() const bool coco_rsdos_image::can_write() const { - return false; + return true; } @@ -197,7 +230,7 @@ bool coco_rsdos_impl::validate_filename(std::string_view name) //------------------------------------------------- coco_rsdos_impl::coco_rsdos_impl(fsblk_t &blockdev) - : filesystem_t(blockdev, 256) + : filesystem_t(blockdev, SECTOR_SIZE) { } @@ -206,14 +239,14 @@ coco_rsdos_impl::coco_rsdos_impl(fsblk_t &blockdev) // coco_rsdos_impl::metadata //------------------------------------------------- -std::pair<err_t, meta_data> coco_rsdos_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> coco_rsdos_impl::metadata(const std::vector<std::string> &path) { // attempt to find the file const std::optional<rsdos_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, get_metadata_from_dirent(*dirent)); + return std::make_pair(std::error_condition(), get_metadata_from_dirent(*dirent)); } @@ -221,16 +254,16 @@ std::pair<err_t, meta_data> coco_rsdos_impl::metadata(const std::vector<std::str // coco_rsdos_impl::directory_contents //------------------------------------------------- -std::pair<err_t, std::vector<dir_entry>> coco_rsdos_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> coco_rsdos_impl::directory_contents(const std::vector<std::string> &path) { std::vector<dir_entry> results; - auto callback = [this, &results](const rsdos_dirent &dirent) + auto const callback = [this, &results](u8 s, u8 i, const rsdos_dirent &dirent) { results.emplace_back(dir_entry_type::file, get_metadata_from_dirent(dirent)); return false; }; iterate_directory_entries(callback); - return std::make_pair(ERR_OK, std::move(results)); + return std::make_pair(std::error_condition(), std::move(results)); } @@ -238,12 +271,12 @@ std::pair<err_t, std::vector<dir_entry>> coco_rsdos_impl::directory_contents(con // coco_rsdos_impl::file_read //------------------------------------------------- -std::pair<err_t, std::vector<u8>> coco_rsdos_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> coco_rsdos_impl::file_read(const std::vector<std::string> &path) { // attempt to find the file const std::optional<rsdos_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); std::vector<u8> result; u8 granule; @@ -264,11 +297,10 @@ std::pair<err_t, std::vector<u8>> coco_rsdos_impl::file_read(const std::vector<s { // read this sector auto block = read_sector(track, sector); - const u8 *data = block.rodata(); - u16 data_length = std::min(byte_count, u16(256)); + u16 data_length = std::min(byte_count, u16(SECTOR_SIZE)); // and append it to the results - memcpy(result.data() + current_size, data, data_length); + block->read(0, result.data() + current_size, data_length); // and advance current_size += data_length; @@ -276,7 +308,7 @@ std::pair<err_t, std::vector<u8>> coco_rsdos_impl::file_read(const std::vector<s sector++; } } - return std::make_pair(ERR_OK, std::move(result)); + return std::make_pair(std::error_condition(), std::move(result)); } @@ -284,23 +316,248 @@ std::pair<err_t, std::vector<u8>> coco_rsdos_impl::file_read(const std::vector<s // coco_rsdos_impl::format //------------------------------------------------- -err_t coco_rsdos_impl::format(const meta_data &meta) +std::error_condition coco_rsdos_impl::format(const meta_data &meta) { // formatting RS-DOS is easy - just fill everything with 0xFF - m_blockdev.fill(0xFF); - return ERR_OK; + m_blockdev.fill_all(0xFF); + return std::error_condition(); +} + + +std::pair<std::error_condition, std::string> coco_rsdos_impl::build_direntry_filename(const std::string &filename) +{ + // The manual does not say anything about valid characters for a file name. + const std::regex filename_regex("([^.]{0,8})(\\.([^.]{0,3}))?"); + std::smatch smatch; + if (!std::regex_match(filename, smatch, filename_regex)) + return std::make_pair(error::invalid_name, std::string()); + if (smatch.size() != 4) + return std::make_pair(error::invalid_name, std::string()); + + std::string fname; + fname.resize(FNAME_LENGTH, ' '); + + for (int i = 0; i < 8 && i < smatch.str(1).size(); i++) + fname[i] = smatch.str(1)[i]; + + for (int j = 0; j < 3 && j < smatch.str(3).size(); j++) + fname[8 + j] = smatch.str(3)[j]; + + return std::make_pair(std::error_condition(), std::move(fname)); +} + + +std::error_condition coco_rsdos_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +{ + if (!path.empty()) + return error::unsupported; + + const std::string filename = meta.get_string(meta_name::name, ""); + auto [err, fname] = build_direntry_filename(filename); + if (err) + return err; + + bool found_entry = false; + u8 dir_sector = 0; + u8 file_index = 0; + for (dir_sector = 3; !found_entry && dir_sector <= TRACK_SECTOR_COUNT; dir_sector++) + { + auto dir_block = read_sector(DIRECTORY_TRACK, dir_sector); + + for (file_index = 0; !found_entry && file_index < SECTOR_DIRECTORY_ENTRY_COUNT; file_index++) + { + const u8 first_byte = dir_block->r8(file_index * DIRECTORY_ENTRY_SIZE); + // 0xff marks the end of the directory, 0x00 marks a deleted file + found_entry = (first_byte == 0xff || first_byte == 0x00); + if (found_entry) + { + for (int i = 0; i < DIRECTORY_ENTRY_SIZE; i++) + dir_block->w8(file_index * DIRECTORY_ENTRY_SIZE + i, 0); + + auto [cerr, granule] = claim_granule(); + if (cerr != std::error_condition()) + return cerr; + + dir_block->wstr(file_index * DIRECTORY_ENTRY_SIZE + 0, fname); + dir_block->w8(file_index * DIRECTORY_ENTRY_SIZE + OFFSET_FIRST_GRANULE, granule); + // The file type, ASCII flag, and number of bytes in last sector of file will be set during writing. + } + } + } + if (!found_entry) + return error::no_space; + + return std::error_condition(); +} + + +std::error_condition coco_rsdos_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +{ + if (path.size() != 1) + return error::not_found; + const std::string &target = path[0]; + + std::optional<rsdos_dirent> result; + u8 dir_sector = 0; + u8 dir_file_index = 0; + auto const callback = [&result, &target, &dir_sector, &dir_file_index](u8 s, u8 i, const rsdos_dirent &dirent) + { + const bool found = get_filename_from_dirent(dirent) == target; + if (found) + { + result = dirent; + dir_sector = s; + dir_file_index = i; + } + return found; + }; + iterate_directory_entries(callback); + + if (!result) + return error::not_found; + + const size_t data_length = data.size(); + const u8 max_granule = maximum_granules(); + u8 granule = result->m_first_granule; + u8 granule_sector = 1; + size_t offset = 0; + u16 bytes_in_last_sector = 0; + u8 linked_granule = read_granule_map(granule); + + while (offset < data_length) + { + auto data_block = read_granule_sector(granule, granule_sector); + bytes_in_last_sector = (data_length - offset) > SECTOR_SIZE ? SECTOR_SIZE : data_length - offset; + data_block->write(0, data.data() + offset, bytes_in_last_sector); + offset += SECTOR_SIZE; + write_granule_map(granule, FILE_LAST_GRANULE_INDICATOR + granule_sector); + if (offset < data_length) + { + granule_sector++; + if (granule_sector > GRANULE_SECTOR_COUNT) + { + // Re-use linked granule or claim a new granule + if (linked_granule < max_granule) + { + granule = linked_granule; + linked_granule = read_granule_map(linked_granule); + } + else + { + auto [err, next_granule] = claim_granule(); + if (err) + return err; + write_granule_map(granule, next_granule); + granule = next_granule; + } + granule_sector = 1; + } + } + } + + // Free unused space + while (linked_granule < max_granule) + { + const u8 granule_to_free = linked_granule; + linked_granule = read_granule_map(granule_to_free); + write_granule_map(granule_to_free, 0xff); + } + + // Update directory entry + auto dir_block = read_sector(DIRECTORY_TRACK, dir_sector); + dir_block->w8(dir_file_index * DIRECTORY_ENTRY_SIZE + OFFSET_FILE_TYPE, determine_file_type(data)); + dir_block->w8(dir_file_index * DIRECTORY_ENTRY_SIZE + OFFSET_ASCII_FLAG, is_ascii(data) ? 0xff : 0x00); + dir_block->w16b(dir_file_index * DIRECTORY_ENTRY_SIZE + OFFSET_LAST_SECTOR_BYTES, bytes_in_last_sector); + + return std::error_condition(); +} + + +bool coco_rsdos_impl::is_ascii(const std::vector<u8> &data) const +{ + const size_t data_length = data.size(); + + if (data_length == 0) + return false; + + for (int i = 0; i < data_length; i++) + { + if (!(data[i] == 0x0d || data[i] == 0x0a || (data[i] >= 0x20 && data[i] < 0x60))) + return false; + } + + return true; +} + + +u8 coco_rsdos_impl::determine_file_type(const std::vector<u8> &data) const +{ + if (is_ascii(data)) + { + // TODO: Distinguish between BASIC code and text editor data + return FILE_TYPE_BASIC; + } + + const size_t data_length = data.size(); + // Binary BASIC code seems to begin with ff <16bit size> 26 + if (data_length > 4 && data[0] == 0xff && data[3] == 0x26 && ((data[1] << 8) | data[2]) == data_length - 3) + return FILE_TYPE_BASIC; + + // TODO: Distinguish between Machine Code and Basic Data + + return FILE_TYPE_MACHINE_CODE; +} + + +std::pair<std::error_condition, u8> coco_rsdos_impl::claim_granule() +{ + // Granules are likely not assigned in this order on hardware. + auto granule_block = read_sector(DIRECTORY_TRACK, 2); + for (int g = 0; g < maximum_granules(); g++) + { + if (granule_block->r8(g) == 0xff) + { + granule_block->w8(g, FILE_LAST_GRANULE_INDICATOR); + return std::make_pair(std::error_condition(), g); + } + } + return std::make_pair(error::no_space, 0); +} + + +void coco_rsdos_impl::write_granule_map(u8 granule, u8 map_data) +{ + auto granule_block = read_sector(DIRECTORY_TRACK, 2); + granule_block->w8(granule, map_data); +} + + +u8 coco_rsdos_impl::read_granule_map(u8 granule) const +{ + auto granule_block = read_sector(DIRECTORY_TRACK, 2); + return granule_block->r8(granule); } //------------------------------------------------- -// fsblk_t::block_t coco_rsdos_impl::read_sector +// coco_rsdos_impl::read_sector //------------------------------------------------- -fsblk_t::block_t coco_rsdos_impl::read_sector(int track, int sector) const +fsblk_t::block_t::ptr coco_rsdos_impl::read_sector(int track, int sector) const { // the CoCo RS-DOS world thinks in terms of tracks/sectors, but we have a block device // abstraction - return m_blockdev.get(track * 18 + sector - 1); + return m_blockdev.get(track * TRACK_SECTOR_COUNT + sector - 1); +} + + +fsblk_t::block_t::ptr coco_rsdos_impl::read_granule_sector(u8 granule, u8 sector) const +{ + // Track 17 does not hold granules + if (granule < (DIRECTORY_TRACK * TRACK_GRANULE_COUNT)) + return m_blockdev.get(granule * GRANULE_SECTOR_COUNT + sector - 1); + else + return m_blockdev.get((granule + TRACK_GRANULE_COUNT) * GRANULE_SECTOR_COUNT + sector - 1); } @@ -311,7 +568,7 @@ fsblk_t::block_t coco_rsdos_impl::read_sector(int track, int sector) const u8 coco_rsdos_impl::maximum_granules() const { u32 sector_count = m_blockdev.block_count(); - u32 granule_count = (sector_count / 9) - 2; + u32 granule_count = (sector_count / GRANULE_SECTOR_COUNT) - 2; return granule_count <= 0xFF ? u8(granule_count) : 0xFF; } @@ -327,7 +584,7 @@ std::optional<coco_rsdos_impl::rsdos_dirent> coco_rsdos_impl::dirent_from_path(c const std::string &target = path[0]; std::optional<rsdos_dirent> result; - auto callback = [&result, &target](const rsdos_dirent &dirent) + auto const callback = [&result, &target](u8 s, u8 i, const rsdos_dirent &dirent) { bool found = get_filename_from_dirent(dirent) == target; if (found) @@ -343,28 +600,29 @@ std::optional<coco_rsdos_impl::rsdos_dirent> coco_rsdos_impl::dirent_from_path(c // coco_rsdos_impl::iterate_directory_entries //------------------------------------------------- -void coco_rsdos_impl::iterate_directory_entries(const std::function<bool(const rsdos_dirent &dirent)> &callback) +template <typename T> +void coco_rsdos_impl::iterate_directory_entries(T &&callback) { bool done = false; for (int dir_sector = 3; !done && dir_sector <= 18; dir_sector++) { // read this directory sector - auto dir_block = read_sector(17, dir_sector); - const rsdos_dirent_sector §or = *reinterpret_cast<const rsdos_dirent_sector *>(dir_block.rodata()); + auto dir_block = read_sector(DIRECTORY_TRACK, dir_sector); + const rsdos_dirent_sector §or = *reinterpret_cast<const rsdos_dirent_sector *>(dir_block->rodata()); // and loop through all entries - for (const auto &ent : sector.m_entries) + for (int file_index = 0; file_index < 8; file_index++) { // 0xFF marks the end of the directory - if (ent.m_dirent.m_filename[0] == '\xFF') + if (sector.m_entries[file_index].m_dirent.m_filename[0] == '\xFF') { done = true; } else { // 0x00 marks a deleted file - if (ent.m_dirent.m_filename[0] != '\0') - done = callback(ent.m_dirent); + if (sector.m_entries[file_index].m_dirent.m_filename[0] != '\0') + done = callback(dir_sector, 0, sector.m_entries[file_index].m_dirent); } if (done) @@ -427,7 +685,7 @@ std::string coco_rsdos_impl::get_filename_from_dirent(const rsdos_dirent &dirent //------------------------------------------------- coco_rsdos_impl::granule_iterator::granule_iterator(coco_rsdos_impl &fs, const rsdos_dirent &dirent) - : m_granule_map(fs.read_sector(17, 2)) + : m_granule_map(fs.read_sector(DIRECTORY_TRACK, 2)) , m_current_granule(dirent.m_first_granule) , m_maximum_granules(fs.maximum_granules()) , m_last_sector_bytes((u16(dirent.m_last_sector_bytes_msb) << 8) | dirent.m_last_sector_bytes_lsb) @@ -450,13 +708,13 @@ bool coco_rsdos_impl::granule_iterator::next(u8 &granule, u16 &byte_count) if (m_current_granule) { std::optional<u8> next_granule; - const u8 *granule_map_data = m_granule_map.rodata(); + const u8 *granule_map_data = m_granule_map->rodata(); if (granule_map_data[*m_current_granule] < m_maximum_granules) { // this entry points to the next granule success = true; granule = *m_current_granule; - byte_count = 9 * 256; + byte_count = GRANULE_SECTOR_COUNT * SECTOR_SIZE; next_granule = granule_map_data[*m_current_granule]; // check for cycles, which should only happen if the disk is corrupt (or not in RS-DOS format) @@ -465,13 +723,13 @@ bool coco_rsdos_impl::granule_iterator::next(u8 &granule, u16 &byte_count) else m_visited_granules.set(*next_granule); } - else if (granule_map_data[*m_current_granule] >= 0xC0 && granule_map_data[*m_current_granule] <= 0xC9) + else if (granule_map_data[*m_current_granule] >= FILE_LAST_GRANULE_INDICATOR && granule_map_data[*m_current_granule] <= FILE_LAST_GRANULE_INDICATOR + GRANULE_SECTOR_COUNT) { // this is the last granule in the file success = true; granule = *m_current_granule; u16 sector_count = std::max(granule_map_data[*m_current_granule], u8(0xC1)) - 0xC1; - byte_count = sector_count * 256 + m_last_sector_bytes; + byte_count = sector_count * SECTOR_SIZE + m_last_sector_bytes; next_granule = std::nullopt; } else diff --git a/src/lib/formats/fs_fat.cpp b/src/lib/formats/fs_fat.cpp index f4cd99e36ed..8e47bbc5abe 100644 --- a/src/lib/formats/fs_fat.cpp +++ b/src/lib/formats/fs_fat.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nathan Woods +// copyright-holders:Nathan Woods,Wilbert Pol /*************************************************************************** fs_fat.cpp @@ -7,11 +7,13 @@ PC FAT disk images Current Limitations: - - Read only - Only supports floppy disks - No FAT32 support - No Long Filenames Support + Removal of files is untested; floptool does not have a command to delete + a file. + ***************************************************************************** Master boot record format: @@ -66,13 +68,13 @@ 14 2 Reserved sector count (including boot sector) 16 1 Number of FATs (file allocation tables) 17 2 Number of root directory entries - 19 2 Total sectors (bits 0-15) + 19 2 Total sectors (0 if 0x10000 or more) 21 1 Media descriptor 22 2 Sectors per FAT 24 2 Sectors per track 26 2 Number of heads 28 4 Hidden sectors - 32 4 Total sectors (bits 16-47) + 32 4 Total sectors (0 if less than 0x10000) 36 1 Physical drive number 37 1 Current head 38 1 Signature @@ -147,6 +149,9 @@ #include "strformat.h" #include <optional> +#include <regex> +#include <string_view> + using namespace fs; @@ -163,41 +168,58 @@ namespace { class directory_entry { public: - static const int SIZE = 32; - - directory_entry(const fsblk_t::block_t &block, u32 offset) + static constexpr int SIZE = 32; + static constexpr int OFFSET_FNAME = 0; + static constexpr int FNAME_LENGTH = 11; + static constexpr int OFFSET_ATTRIBUTES = 11; + static constexpr int OFFSET_CREATE_DATETIME = 14; + static constexpr int OFFSET_START_CLUSTER_HI = 20; + static constexpr int OFFSET_MODIFIED_DATETIME = 22; + static constexpr int OFFSET_START_CLUSTER = 26; + static constexpr int OFFSET_FILE_SIZE = 28; + static constexpr u8 DELETED_FILE_MARKER = 0xe5; + static constexpr u8 ATTR_READ_ONLY = 0x01; + static constexpr u8 ATTR_HIDDEN = 0x02; + static constexpr u8 ATTR_SYSTEM = 0x04; + static constexpr u8 ATTR_VOLUME_LABEL = 0x08; + static constexpr u8 ATTR_DIRECTORY = 0x10; + static constexpr u8 ATTR_ARCHIVE = 0x20; + + directory_entry(fsblk_t::block_t::ptr block, u32 offset) : m_block(block) , m_offset(offset) { } - std::string_view raw_stem() const { return std::string_view((const char *) &m_block.rodata()[m_offset + 0], 8); } - std::string_view raw_ext() const { return std::string_view((const char *) &m_block.rodata()[m_offset + 8], 3); } - u8 attributes() const { return m_block.r8(m_offset + 11); } - u32 raw_create_datetime() const { return m_block.r32l(m_offset + 14); } - u32 raw_modified_datetime() const { return m_block.r32l(m_offset + 22); } - u32 start_cluster() const { return ((u32)m_block.r16l(m_offset + 20)) << 16 | m_block.r16l(m_offset + 26); } - u32 file_size() const { return m_block.r32l(m_offset + 28); } + std::string_view raw_stem() const { return m_block->rstr(m_offset + OFFSET_FNAME, 8); } + std::string_view raw_ext() const { return m_block->rstr(m_offset + OFFSET_FNAME + 8, 3); } + u8 attributes() const { return m_block->r8(m_offset + OFFSET_ATTRIBUTES); } + u32 raw_create_datetime() const { return m_block->r32l(m_offset + OFFSET_CREATE_DATETIME); } + u32 raw_modified_datetime() const { return m_block->r32l(m_offset + OFFSET_MODIFIED_DATETIME); } + u32 start_cluster() const { return ((u32)m_block->r16l(m_offset + OFFSET_START_CLUSTER_HI)) << 16 | m_block->r16l(m_offset + OFFSET_START_CLUSTER); } + u32 file_size() const { return m_block->r32l(m_offset + OFFSET_FILE_SIZE); } bool is_read_only() const { return (attributes() & 0x01) != 0x00; } bool is_hidden() const { return (attributes() & 0x02) != 0x00; } bool is_system() const { return (attributes() & 0x04) != 0x00; } bool is_volume_label() const { return (attributes() & 0x08) != 0x00; } + bool is_long_file_name() const { return attributes() == 0x0f; } bool is_subdirectory() const { return (attributes() & 0x10) != 0x00; } bool is_archive() const { return (attributes() & 0x20) != 0x00; } - bool is_deleted() const { return m_block.r8(m_offset) == DELETED_FILE_MARKER; } + bool is_deleted() const { return m_block->r8(m_offset) == DELETED_FILE_MARKER; } std::string name() const; meta_data metadata() const; -private: - static constexpr u8 DELETED_FILE_MARKER = 0xe5; + void set_file_size(u32 file_size) { m_block->w32l(m_offset + OFFSET_FILE_SIZE, file_size); } + void set_raw_modified_datetime(u32 datetime) { m_block->w32l(m_offset + OFFSET_MODIFIED_DATETIME, datetime); } + void mark_deleted() { m_block->w8(m_offset + OFFSET_FNAME, DELETED_FILE_MARKER); } - fsblk_t::block_t m_block; - u32 m_offset; +private: + fsblk_t::block_t::ptr m_block; + u32 m_offset; }; - // ======================> directory_span class directory_span @@ -218,7 +240,7 @@ class impl : public filesystem_t { public: // ctor/dtor - impl(fsblk_t &blockdev, fsblk_t::block_t &&boot_sector_block, std::vector<u8> &&file_allocation_table, u32 starting_sector, u32 sector_count, u16 reserved_sector_count, u8 bits_per_fat_entry); + impl(fsblk_t &blockdev, fsblk_t::block_t::ptr &&boot_sector_block, std::vector<u8> &&file_allocation_table, u32 starting_sector, u32 sector_count, u16 reserved_sector_count, u8 bits_per_fat_entry); virtual ~impl() = default; // accessors @@ -228,27 +250,60 @@ public: // virtuals virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; + virtual std::error_condition remove(const std::vector<std::string> &path) override; // methods std::vector<u32> get_sectors_from_fat(const directory_entry &dirent) const; + // Boot sector settings + static constexpr u32 OFFSET_BYTES_PER_SECTOR = 0x0b; + static constexpr u32 OFFSET_CLUSTER_SECTOR_COUNT = 0x0d; + static constexpr u32 OFFSET_RESERVED_SECTOR_COUNT = 0x0e; + static constexpr u32 OFFSET_FAT_COUNT = 0x10; + static constexpr u32 OFFSET_DIRECTORY_ENTRY_COUNT = 0x11; + static constexpr u32 OFFSET_FAT_SECTOR_COUNT = 0x16; + private: - fsblk_t::block_t m_boot_sector_block; + static constexpr u32 FIRST_VALID_CLUSTER = 2; + + fsblk_t::block_t::ptr m_boot_sector_block; std::vector<u8> m_file_allocation_table; u32 m_starting_sector; u32 m_sector_count; u16 m_reserved_sector_count; u16 m_bytes_per_sector; + u16 m_root_directory_size; + u16 m_sectors_per_cluster; + u8 m_fat_count; + u16 m_fat_sector_count; u8 m_bits_per_fat_entry; + u32 m_last_cluster_indicator; + u32 m_last_valid_cluster; // methods std::optional<directory_entry> find_entity(const std::vector<std::string> &path) const; directory_span::ptr find_directory(std::vector<std::string>::const_iterator path_begin, std::vector<std::string>::const_iterator path_end) const; std::optional<directory_entry> find_child(const directory_span ¤t_dir, std::string_view target) const; - void iterate_directory_entries(const directory_span &dir, const std::function<bool(const directory_entry &dirent)> &callback) const; + template <typename T> void iterate_directory_entries(const directory_span &dir, T &&callback) const; + bool is_valid_short_filename(std::string const &filename); + std::error_condition build_direntry_filename(std::string const &filename, std::string &fname); + std::error_condition file_create_root(std::string &fname, u8 attributes = 0); + std::error_condition file_create_directory(directory_entry &dirent, std::string &fname, u8 attributes = 0); + std::error_condition file_create_sector(u32 sector, std::string &fname, u8 attributes); + std::error_condition initialize_directory(u32 directory_cluster, u32 parent_cluster); + std::error_condition initialize_directory_entry(fsblk_t::block_t &dirblk, u32 offset, std::string_view fname, u8 attributes, u32 start_cluster); + std::error_condition free_clusters(u32 start_cluster); + void clear_cluster_sectors(u32 cluster, u8 fill_byte); + u32 first_cluster_sector(u32 cluster); + u32 get_next_cluster(u32 cluster); + void set_next_cluster(u32 cluster, u32 next_cluster); + u32 find_free_cluster(); + }; @@ -297,7 +352,7 @@ private: namespace { bool validate_filename(std::string_view name) { - auto is_invalid_filename_char = [](char ch) + auto const is_invalid_filename_char = [] (char ch) { return ch == '\0' || strchr("\\/:*?\"<>|", ch); }; @@ -316,15 +371,27 @@ util::arbitrary_datetime decode_fat_datetime(u32 dt) util::arbitrary_datetime result; memset(&result, 0, sizeof(result)); - result.year = ((dt >> 25) & 0x7F) + 1980; - result.month = (dt >> 21) & 0x0F; - result.day_of_month = (dt >> 16) & 0x1F; - result.hour = (dt >> 11) & 0x1F; - result.minute = (dt >> 5) & 0x3F; - result.second = ((dt >> 0) & 0x1F) * 2; + result.year = ((dt >> 25) & 0x7f) + 1980; + result.month = (dt >> 21) & 0x0f; + result.day_of_month = (dt >> 16) & 0x1f; + result.hour = (dt >> 11) & 0x1f; + result.minute = (dt >> 5) & 0x3f; + result.second = ((dt >> 0) & 0x1f) * 2; return result; } +u32 encode_now_fat_datetime() +{ + auto now = util::arbitrary_datetime::now(); + + return u32((((now.year - 1980) & 0x7f) << 25) | + ((now.month & 0x0f) << 21) | + ((now.day_of_month & 0x1f) << 16) | + ((now.hour & 0x1f) << 11) | + ((now.minute & 0x3f) << 5) | + ((now.second >> 1) & 0x1f)); +} + } @@ -354,7 +421,7 @@ bool fs::fat_image::can_read() const bool fs::fat_image::can_write() const { - return false; + return true; } @@ -385,8 +452,8 @@ char fs::fat_image::directory_separator() const std::vector<meta_description> fs::fat_image::volume_meta_description() const { std::vector<meta_description> results; - results.emplace_back(meta_name::name, "UNTITLED", false, [](const meta_value &m) { return m.as_string().size() <= 11; }, "Volume name, up to 11 characters"); - results.emplace_back(meta_name::oem_name, "", false, [](const meta_value &m) { return m.as_string().size() <= 8; }, "OEM name, up to 8 characters"); + results.emplace_back(meta_name::name, "UNTITLED", false, [] (const meta_value &m) { return validate_filename(m.as_string()); }, "Volume name"); + results.emplace_back(meta_name::oem_name, "", false, [] (const meta_value &m) { return m.as_string().size() <= 8; }, "OEM name, up to 8 characters"); return results; } @@ -398,7 +465,7 @@ std::vector<meta_description> fs::fat_image::volume_meta_description() const std::vector<meta_description> fs::fat_image::file_meta_description() const { std::vector<meta_description> results; - results.emplace_back(meta_name::name, "", false, [](const meta_value &m) { return validate_filename(m.as_string()); }, "File name"); + results.emplace_back(meta_name::name, "", false, [] (const meta_value &m) { return validate_filename(m.as_string()); }, "File name"); results.emplace_back(meta_name::creation_date, util::arbitrary_datetime::now(), false, nullptr, "Creation time"); results.emplace_back(meta_name::modification_date, util::arbitrary_datetime::now(), false, nullptr, "Modification time"); results.emplace_back(meta_name::length, 0, true, nullptr, "Size of the file in bytes"); @@ -413,7 +480,7 @@ std::vector<meta_description> fs::fat_image::file_meta_description() const std::vector<meta_description> fs::fat_image::directory_meta_description() const { std::vector<meta_description> results; - results.emplace_back(meta_name::name, "", false, [](const meta_value &m) { return validate_filename(m.as_string()); }, "File name"); + results.emplace_back(meta_name::name, "", false, [] (const meta_value &m) { return validate_filename(m.as_string()); }, "File name"); results.emplace_back(meta_name::creation_date, util::arbitrary_datetime::now(), false, nullptr, "Creation time"); results.emplace_back(meta_name::modification_date, util::arbitrary_datetime::now(), false, nullptr, "Modification time"); return results; @@ -427,19 +494,19 @@ std::vector<meta_description> fs::fat_image::directory_meta_description() const std::unique_ptr<filesystem_t> fs::fat_image::mount_partition(fsblk_t &blockdev, u32 starting_sector, u32 sector_count, u8 bits_per_fat_entry) { // load the boot sector block and get some basic info - fsblk_t::block_t boot_sector_block = blockdev.get(starting_sector); - u16 reserved_sector_count = boot_sector_block.r16l(14); + fsblk_t::block_t::ptr boot_sector_block = blockdev.get(starting_sector); + u16 reserved_sector_count = boot_sector_block->r16l(impl::OFFSET_RESERVED_SECTOR_COUNT); // load all file allocation table sectors - u32 fat_count = boot_sector_block.r8(16); - u32 sectors_per_fat = boot_sector_block.r16l(22); - u16 bytes_per_sector = boot_sector_block.r16l(11); + u32 fat_count = boot_sector_block->r8(impl::OFFSET_FAT_COUNT); + u32 sectors_per_fat = boot_sector_block->r16l(impl::OFFSET_FAT_SECTOR_COUNT); + u16 bytes_per_sector = boot_sector_block->r16l(impl::OFFSET_BYTES_PER_SECTOR); std::vector<u8> file_allocation_table; file_allocation_table.reserve(fat_count * sectors_per_fat * bytes_per_sector); for (auto i = 0; i < fat_count * sectors_per_fat; i++) { - fsblk_t::block_t fatblk = blockdev.get(starting_sector + reserved_sector_count + i); - file_allocation_table.insert(file_allocation_table.end(), fatblk.rodata(), fatblk.rodata() + bytes_per_sector); + fsblk_t::block_t::ptr fatblk = blockdev.get(starting_sector + reserved_sector_count + i); + file_allocation_table.insert(file_allocation_table.end(), fatblk->rodata(), fatblk->rodata() + bytes_per_sector); } // and return the implementation @@ -481,16 +548,24 @@ meta_data directory_entry::metadata() const // impl ctor //------------------------------------------------- -impl::impl(fsblk_t &blockdev, fsblk_t::block_t &&boot_sector_block, std::vector<u8> &&file_allocation_table, u32 starting_sector, u32 sector_count, u16 reserved_sector_count, u8 bits_per_fat_entry) +impl::impl(fsblk_t &blockdev, fsblk_t::block_t::ptr &&boot_sector_block, std::vector<u8> &&file_allocation_table, u32 starting_sector, u32 sector_count, u16 reserved_sector_count, u8 bits_per_fat_entry) : filesystem_t(blockdev, 512) , m_boot_sector_block(std::move(boot_sector_block)) , m_file_allocation_table(std::move(file_allocation_table)) , m_starting_sector(starting_sector) , m_sector_count(sector_count) , m_reserved_sector_count(reserved_sector_count) - , m_bytes_per_sector(m_boot_sector_block.r16l(11)) + , m_bytes_per_sector(m_boot_sector_block->r16l(OFFSET_BYTES_PER_SECTOR)) + , m_root_directory_size(m_boot_sector_block->r16l(OFFSET_DIRECTORY_ENTRY_COUNT)) + , m_sectors_per_cluster(m_boot_sector_block->r8(OFFSET_CLUSTER_SECTOR_COUNT)) + , m_fat_count(m_boot_sector_block->r8(OFFSET_FAT_COUNT)) + , m_fat_sector_count(m_boot_sector_block->r16l(OFFSET_FAT_SECTOR_COUNT)) , m_bits_per_fat_entry(bits_per_fat_entry) + , m_last_cluster_indicator(((u64)1 << bits_per_fat_entry) - 1) + , m_last_valid_cluster(m_last_cluster_indicator - 0x10) { + if (m_bytes_per_sector == 0) + m_bytes_per_sector = 512; } @@ -500,9 +575,26 @@ impl::impl(fsblk_t &blockdev, fsblk_t::block_t &&boot_sector_block, std::vector< meta_data impl::volume_metadata() { + std::vector<std::string> root_path; + directory_span::ptr root_dir = find_directory(root_path.begin(), root_path.end()); + assert(root_dir); + + // Get the volume label from the root directory, not the extended BPB (whose name field may not be kept up-to-date even when it exists) meta_data results; - results.set(meta_name::name, m_boot_sector_block.rstr(43, 11)); - results.set(meta_name::oem_name, m_boot_sector_block.rstr(3, 8)); + auto const callback = [&results] (const directory_entry &dirent) + { + if (dirent.is_volume_label()) + { + results.set(meta_name::name, dirent.name()); + return true; + } + return false; + }; + iterate_directory_entries(*root_dir, callback); + if (!results.has(meta_name::name)) + results.set(meta_name::name, "UNTITLED"); + + results.set(meta_name::oem_name, m_boot_sector_block->rstr(3, 8)); return results; } @@ -511,13 +603,13 @@ meta_data impl::volume_metadata() // impl::metadata //------------------------------------------------- -std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> impl::metadata(const std::vector<std::string> &path) { std::optional<directory_entry> dirent = find_entity(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, dirent->metadata()); + return std::make_pair(std::error_condition(), dirent->metadata()); } @@ -525,21 +617,24 @@ std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) // impl::directory_contents //------------------------------------------------- -std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) { directory_span::ptr dir = find_directory(path.begin(), path.end()); if (!dir) - return std::make_pair(ERR_NOT_FOUND, std::vector<dir_entry>()); + return std::make_pair(error::not_found, std::vector<dir_entry>()); std::vector<dir_entry> results; - auto callback = [&results](const directory_entry &dirent) + auto const callback = [&results] (const directory_entry &dirent) { - dir_entry_type entry_type = dirent.is_subdirectory() ? dir_entry_type::dir : dir_entry_type::file; - results.emplace_back(entry_type, dirent.metadata()); + if (!dirent.is_volume_label()) + { + dir_entry_type entry_type = dirent.is_subdirectory() ? dir_entry_type::dir : dir_entry_type::file; + results.emplace_back(entry_type, dirent.metadata()); + } return false; }; iterate_directory_entries(*dir, callback); - return std::make_pair(ERR_OK, std::move(results)); + return std::make_pair(std::error_condition(), std::move(results)); } @@ -547,12 +642,14 @@ std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vec // impl::file_read //------------------------------------------------- -std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) { // find the file std::optional<directory_entry> dirent = find_entity(path); - if (!dirent || dirent->is_subdirectory()) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + if (!dirent) + return std::make_pair(error::not_found, std::vector<u8>()); + if (dirent->is_subdirectory()) + return std::make_pair(error::invalid_name, std::vector<u8>()); // get the list of sectors for this file std::vector<u32> sectors = get_sectors_from_fat(*dirent); @@ -564,15 +661,353 @@ std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> // and add data from all sectors for (u32 sector : sectors) { - fsblk_t::block_t block = m_blockdev.get(sector); - const u8 *data = block.rodata(); - size_t length = std::min((size_t)dirent->file_size() - result.size(), (size_t)block.size()); + fsblk_t::block_t::ptr block = m_blockdev.get(sector); + const u8 *data = block->rodata(); + size_t length = std::min((size_t)dirent->file_size() - result.size(), (size_t)block->size()); result.insert(result.end(), data, data + length); } - return std::make_pair(ERR_OK, std::move(result)); + return std::make_pair(std::error_condition(), std::move(result)); +} + + +bool impl::is_valid_short_filename(std::string const &filename) +{ + /* + Valid characters in DOS file names: + - Upper case letters A-Z + - Numbers 0-9 + - Space (though there is no way to identify a trailing space) + - ! # $ % & ( ) - @ ^ _ ` { } ~ + - Characters 128-255, except e5 (though the code page is indeterminate) + We currently do not check for characters 128-255. + */ + std::regex filename_regex("([A-Z0-9!#\\$%&\\(\\)\\-@^_`\\{\\}~]{0,8})(\\.([A-Z0-9!#\\$%&\\(\\)\\-@^_`\\{\\}~]{0,3}))?"); + return std::regex_match(filename, filename_regex); +} + + +std::error_condition impl::build_direntry_filename(std::string const &filename, std::string &fname) +{ + std::regex filename_regex("([A-Z0-9!#\\$%&\\(\\)\\-@^_`\\{\\}~]{0,8})(\\.([A-Z0-9!#\\$%&\\(\\)\\-@^_`\\{\\}~]{0,3}))?"); + std::smatch smatch; + if (!std::regex_match(filename, smatch, filename_regex)) + return error::invalid_name; + if (smatch.size() != 4) + return error::invalid_name; + + fname.resize(directory_entry::FNAME_LENGTH, ' '); + + for (int i = 0; i < 8 && i < smatch.str(1).size(); i++) + fname[i] = smatch.str(1)[i]; + + for (int j = 0; j < 3 && j < smatch.str(3).size(); j++) + fname[8 + j] = smatch.str(3)[j]; + + return std::error_condition(); +} + + +std::error_condition impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +{ + std::string filename = meta.get_string(meta_name::name, ""); + std::string fname; + std::error_condition err = build_direntry_filename(filename, fname); + if (err) + return err; + + if (path.empty()) + { + return file_create_root(fname); + } + else + { + // Make sure that all parts of the path exist, creating the path parts as needed. + std::optional<directory_entry> dirent = find_entity(path); + if (!dirent) + { + std::vector<std::string> partial_path; + std::optional<directory_entry> parent_entry; + for (auto const &path_part : path) + { + partial_path.emplace_back(path_part); + std::optional<directory_entry> dir_entry = find_entity(partial_path); + if (!dir_entry) + { + if (!is_valid_short_filename(path_part)) + return error::invalid_name; + + std::string part_fname; + std::error_condition err = build_direntry_filename(path_part, part_fname); + if (err) + return err; + err = !parent_entry ? + file_create_root(part_fname, directory_entry::ATTR_DIRECTORY) : + file_create_directory(parent_entry.value(), part_fname, directory_entry::ATTR_DIRECTORY); + if (err) + return err; + + dir_entry = find_entity(partial_path); + if (!dir_entry) + return error::invalid_name; + + err = initialize_directory(dir_entry->start_cluster(), parent_entry ? parent_entry->start_cluster() : 0); + if (err) + return err; + } + else + { + if (!dir_entry->is_subdirectory()) + return error::invalid_name; + } + parent_entry = dir_entry; + } + + dirent = find_entity(path); + if (!dirent) + return error::invalid_name; + } + + return file_create_directory(*dirent, fname); + } +} + + +std::error_condition impl::initialize_directory(u32 directory_cluster, u32 parent_cluster) +{ + clear_cluster_sectors(directory_cluster, 0x00); + + auto dirblk = m_blockdev.get(first_cluster_sector(directory_cluster)); + + // Add special directory entries for . and .. + std::string dir_fname; + dir_fname.resize(directory_entry::FNAME_LENGTH, ' '); + dir_fname[0] = '.'; + std::error_condition err = initialize_directory_entry(*dirblk, 0, dir_fname, directory_entry::ATTR_DIRECTORY, directory_cluster); + if (err) + return err; + + dir_fname[1] = '.'; + err = initialize_directory_entry(*dirblk, directory_entry::SIZE, dir_fname, directory_entry::ATTR_DIRECTORY, parent_cluster); + if (err) + return err; + + return std::error_condition(); +} + + +std::error_condition impl::initialize_directory_entry(fsblk_t::block_t &dirblk, u32 offset, std::string_view fname, u8 attributes, u32 start_cluster) +{ + if (fname.size() != directory_entry::FNAME_LENGTH) + return error::invalid_name; + + for (int i = 0; i < directory_entry::SIZE; i += 4) + dirblk.w32l(offset + i, 0); + + dirblk.wstr(offset + directory_entry::OFFSET_FNAME, fname); + dirblk.w8(offset + directory_entry::OFFSET_ATTRIBUTES, attributes); + dirblk.w32l(offset + directory_entry::OFFSET_CREATE_DATETIME, encode_now_fat_datetime()); + dirblk.w32l(offset + directory_entry::OFFSET_MODIFIED_DATETIME, encode_now_fat_datetime()); + dirblk.w16l(offset + directory_entry::OFFSET_START_CLUSTER_HI, u16(start_cluster >> 16)); + dirblk.w16l(offset + directory_entry::OFFSET_START_CLUSTER, u16(start_cluster & 0xffff)); + + return std::error_condition(); +} + + +std::error_condition impl::file_create_root(std::string &fname, u8 attributes) +{ + const u32 first_directory_sector = m_starting_sector + m_reserved_sector_count + ((u32)m_file_allocation_table.size() / m_bytes_per_sector); + const u32 directory_sector_count = (m_root_directory_size * directory_entry::SIZE) / m_bytes_per_sector; + for (u32 sector = first_directory_sector; sector < first_directory_sector + directory_sector_count; sector++) + { + std::error_condition err = file_create_sector(sector, fname, attributes); + if (err != error::not_found) + return err; + } + return error::no_space; +} + + +std::error_condition impl::file_create_directory(directory_entry &dirent, std::string &fname, u8 attributes) +{ + u32 current_cluster = dirent.start_cluster(); + do { + const u32 first_sector = first_cluster_sector(current_cluster); + for (int i = 0; i < m_sectors_per_cluster; i++) + { + std::error_condition err = file_create_sector(first_sector + i, fname, attributes); + if (err != error::not_found) + return err; + } + + // File could not be created yet. Move to next cluster, allocating a new cluster when needed. + u32 next_cluster = get_next_cluster(current_cluster); + if (next_cluster >= m_last_valid_cluster) + { + next_cluster = find_free_cluster(); + if (next_cluster == 0) + return error::no_space; + + set_next_cluster(current_cluster, next_cluster); + set_next_cluster(next_cluster, m_last_cluster_indicator); + + clear_cluster_sectors(next_cluster, 0x00); + } + current_cluster = next_cluster; + } while (current_cluster > FIRST_VALID_CLUSTER && current_cluster < m_last_valid_cluster); + return error::no_space; +} + + +u32 impl::first_cluster_sector(u32 cluster) +{ + return m_starting_sector + m_reserved_sector_count + + ((u32)m_file_allocation_table.size() / m_bytes_per_sector) + + ((m_root_directory_size + 1) / dirents_per_sector()) + + ((cluster - FIRST_VALID_CLUSTER) * m_sectors_per_cluster); +} + + +void impl::clear_cluster_sectors(u32 cluster, u8 fill_byte) +{ + const u32 sector = first_cluster_sector(cluster); + for (int i = 0; i < m_sectors_per_cluster; i++) + { + auto dirblk = m_blockdev.get(sector + i); + for (int offset = 0; offset < m_bytes_per_sector; offset++) + dirblk->w8(offset, fill_byte); + } } +// Returns error::not_found when no room could be found to create the file in the sector. +std::error_condition impl::file_create_sector(u32 sector, std::string &fname, u8 attributes) +{ + auto dirblk = m_blockdev.get(sector); + for (u32 blkoffset = 0; blkoffset < m_bytes_per_sector; blkoffset += directory_entry::SIZE) + { + u8 first_byte = dirblk->r8(blkoffset); + if (first_byte == 0x00 || first_byte == directory_entry::DELETED_FILE_MARKER) + { + u32 start_cluster = find_free_cluster(); + if (start_cluster == 0) + return error::no_space; + set_next_cluster(start_cluster, m_last_cluster_indicator); + + std::error_condition err = initialize_directory_entry(*dirblk, blkoffset, fname, attributes, start_cluster); + if (err) + return err; + + return std::error_condition(); + } + } + return error::not_found; +} + + +std::error_condition impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +{ + std::optional<directory_entry> dirent = find_entity(path); + if (!dirent) + return error::not_found; + + if (dirent->is_subdirectory()) + return error::invalid_name; + + u32 current_length = dirent->file_size(); + const size_t data_length = data.size(); + const u32 bytes_per_cluster = m_sectors_per_cluster * bytes_per_sector(); + const u32 current_clusters = (current_length + bytes_per_cluster - 1) / bytes_per_cluster; + const u32 required_clusters = (data_length + bytes_per_cluster - 1) / bytes_per_cluster; + + if (required_clusters > current_clusters) + { + u32 current_cluster = dirent->start_cluster(); + u32 next_cluster = 0; + do { + next_cluster = get_next_cluster(current_cluster); + if (next_cluster < FIRST_VALID_CLUSTER) + return error::invalid_block; + } while (next_cluster < m_last_valid_cluster); + for (int i = current_clusters; i < required_clusters; i++) + { + u32 free_cluster = find_free_cluster(); + if (free_cluster < FIRST_VALID_CLUSTER) + return error::no_space; + + set_next_cluster(current_cluster, free_cluster); + set_next_cluster(free_cluster, m_last_cluster_indicator); + current_cluster = free_cluster; + } + } + if (required_clusters < current_clusters) + { + u32 current_cluster = dirent->start_cluster(); + for (int i = 0; i < required_clusters; i++) + { + current_cluster = get_next_cluster(current_cluster); + } + u32 next_cluster = get_next_cluster(current_cluster); + set_next_cluster(current_cluster, m_last_cluster_indicator); + + std::error_condition err = free_clusters(next_cluster); + if (err) + return err; + } + + auto sectors = get_sectors_from_fat(*dirent); + size_t offset = 0; + for (auto sector : sectors) + { + if (offset < data_length) + { + auto datablk = m_blockdev.get(sector); + u32 bytes = (data_length - offset > m_bytes_per_sector) ? m_bytes_per_sector : data_length - offset; + datablk->write(0, data.data() + offset, bytes); + offset += m_bytes_per_sector; + } + } + + dirent->set_raw_modified_datetime(encode_now_fat_datetime()); + dirent->set_file_size(data_length); + + return std::error_condition(); +} + + +std::error_condition impl::remove(const std::vector<std::string> &path) +{ + if (path.size() != 0) + return error::unsupported; + + std::optional<directory_entry> dirent = find_entity(path); + if (!dirent) + return std::error_condition(); + + // Removing directories is not supported yet + if (dirent->is_subdirectory()) + return error::unsupported; + + dirent->mark_deleted(); + + return std::error_condition(); +} + + +std::error_condition impl::free_clusters(u32 start_cluster) +{ + while (start_cluster < m_last_valid_cluster) + { + if (start_cluster < FIRST_VALID_CLUSTER) + return error::invalid_block; + + u32 next_cluster = get_next_cluster(start_cluster); + set_next_cluster(start_cluster, 0); + start_cluster = next_cluster; + } + return std::error_condition(); +} + //------------------------------------------------- // impl::get_sectors_from_fat //------------------------------------------------- @@ -584,22 +1019,20 @@ std::vector<u32> impl::get_sectors_from_fat(const directory_entry &dirent) const results.reserve(dirent.file_size() / bytes_per_sector()); // get critical information - u8 sectors_per_cluster = m_boot_sector_block.r8(13); - u16 root_directory_entry_count = m_boot_sector_block.r16l(17); - u16 root_directory_sector_count = (root_directory_entry_count + 1) / dirents_per_sector(); - u32 fat_sector_count = (u32)(m_file_allocation_table.size() / m_bytes_per_sector); + u16 root_directory_sector_count = (m_root_directory_size + 1) / dirents_per_sector(); + u32 fat_sector_count = m_fat_count * m_fat_sector_count; u32 data_starting_sector = m_starting_sector + m_reserved_sector_count + fat_sector_count + root_directory_sector_count; - u32 data_cluster_count = (m_sector_count - data_starting_sector) / sectors_per_cluster; + u32 data_cluster_count = (m_sector_count - data_starting_sector) / m_sectors_per_cluster; // find all clusters u32 start_cluster_mask = ((u64)1 << m_bits_per_fat_entry) - 1; u32 cluster = dirent.start_cluster() & start_cluster_mask; - while (cluster >= 2 && cluster < (data_cluster_count + 2)) + while (cluster >= FIRST_VALID_CLUSTER && cluster < (data_cluster_count + 2)) { // add the sectors for this cluster - for (auto i = 0; i < sectors_per_cluster; i++) - results.push_back(data_starting_sector + (cluster - 2) * sectors_per_cluster + i); + for (auto i = 0; i < m_sectors_per_cluster; i++) + results.push_back(data_starting_sector + (cluster - FIRST_VALID_CLUSTER) * m_sectors_per_cluster + i); // determine the bit position of this entry u32 entry_bit_position = cluster * m_bits_per_fat_entry; @@ -623,8 +1056,8 @@ std::vector<u32> impl::get_sectors_from_fat(const directory_entry &dirent) const } // normalize special cluster IDs - if (new_cluster > ((u32)1 << m_bits_per_fat_entry) - 0x10) - new_cluster |= ~(((u32)1 << m_bits_per_fat_entry) - 1); + if (new_cluster > m_last_valid_cluster) + new_cluster |= ~m_last_cluster_indicator; } cluster = new_cluster; } @@ -633,6 +1066,91 @@ std::vector<u32> impl::get_sectors_from_fat(const directory_entry &dirent) const } +u32 impl::get_next_cluster(u32 cluster) +{ + u32 entry_bit_position = cluster * m_bits_per_fat_entry; + u32 new_cluster = 0; + if (entry_bit_position + m_bits_per_fat_entry <= m_file_allocation_table.size() * 8) + { + u32 current_bit = 0; + while (current_bit < m_bits_per_fat_entry) + { + u32 pos = entry_bit_position + current_bit; + u32 shift = pos % 8; + u32 bit_count = std::min(8 - shift, m_bits_per_fat_entry - current_bit); + u32 bits = (m_file_allocation_table[pos / 8] >> shift) & ((1 << bit_count) - 1); + + new_cluster |= (bits << current_bit); + current_bit += bit_count; + } + } + return new_cluster; +} + + +void impl::set_next_cluster(u32 cluster, u32 next_cluster) +{ + const u32 m_fat_start_sector = m_starting_sector + m_reserved_sector_count; + const u32 entry_bit_position = cluster * m_bits_per_fat_entry; + if (entry_bit_position + m_bits_per_fat_entry <= m_file_allocation_table.size() * 8) + { + u32 current_bit = 0; + while (current_bit < m_bits_per_fat_entry) + { + u32 pos = entry_bit_position + current_bit; + u32 shift = pos % 8; + u32 bit_count = std::min(8 - shift, m_bits_per_fat_entry - current_bit); + u32 byte_pos = pos / 8; + u32 mask = ((1 << bit_count) - 1); + m_file_allocation_table[byte_pos] = (m_file_allocation_table[byte_pos] & ~(mask << shift)) | ((next_cluster & mask) << shift); + next_cluster = next_cluster >> bit_count; + current_bit += bit_count; + // Write back to backing blocks + for (int i = 0; i < m_fat_count; i++) + { + u32 fat_sector = m_fat_start_sector + (i * m_fat_sector_count) + (byte_pos / m_bytes_per_sector); + auto fatblk = m_blockdev.get(fat_sector); + fatblk->w8(byte_pos % m_bytes_per_sector, m_file_allocation_table[byte_pos]); + } + } + } +} + + +// Returns 0 if no free cluster could be found +u32 impl::find_free_cluster() +{ + u16 root_directory_sector_count = (m_root_directory_size + 1) / dirents_per_sector(); + u32 fat_sector_count = m_fat_count * m_fat_sector_count; + u32 data_starting_sector = m_starting_sector + m_reserved_sector_count + fat_sector_count + root_directory_sector_count; + u32 data_cluster_count = (m_sector_count - data_starting_sector) / m_sectors_per_cluster; + + for (u32 cluster = FIRST_VALID_CLUSTER; cluster < (data_cluster_count + 2); cluster++) + { + u32 entry_bit_position = cluster * m_bits_per_fat_entry; + + if (entry_bit_position + m_bits_per_fat_entry <= m_file_allocation_table.size() * 8) + { + u32 new_cluster = 0; + u32 current_bit = 0; + while (current_bit < m_bits_per_fat_entry) + { + u32 pos = entry_bit_position + current_bit; + u32 shift = pos % 8; + u32 bit_count = std::min(8 - shift, m_bits_per_fat_entry - current_bit); + u32 bits = (m_file_allocation_table[pos / 8] >> shift) & ((1 << bit_count) - 1); + + new_cluster |= (bits << current_bit); + current_bit += bit_count; + } + + if (new_cluster == 0) + return cluster; + } + } + return 0; +} + //------------------------------------------------- // impl::find_entity //------------------------------------------------- @@ -661,8 +1179,7 @@ directory_span::ptr impl::find_directory(std::vector<std::string>::const_iterato { // the root directory is treated differently u32 first_sector = m_starting_sector + m_reserved_sector_count + (u32)m_file_allocation_table.size() / m_bytes_per_sector; - u16 directory_entry_count = m_boot_sector_block.r16l(17); - directory_span::ptr current_dir = std::make_unique<root_directory_span>(*this, first_sector, directory_entry_count); + directory_span::ptr current_dir = std::make_unique<root_directory_span>(*this, first_sector, m_root_directory_size); // traverse the directory for (auto iter = path_begin; iter != path_end; iter++) @@ -687,7 +1204,7 @@ directory_span::ptr impl::find_directory(std::vector<std::string>::const_iterato std::optional<directory_entry> impl::find_child(const directory_span ¤t_dir, std::string_view target) const { std::optional<directory_entry> result; - auto callback = [&result, target](const directory_entry &dirent) + auto const callback = [&result, target] (const directory_entry &dirent) { bool found = dirent.name() == target; if (found) @@ -703,17 +1220,18 @@ std::optional<directory_entry> impl::find_child(const directory_span ¤t_di // impl::iterate_directory_entries //------------------------------------------------- -void impl::iterate_directory_entries(const directory_span &dir, const std::function<bool(const directory_entry &dirent)> &callback) const +template <typename T> +void impl::iterate_directory_entries(const directory_span &dir, T &&callback) const { std::vector<u32> sectors = dir.get_directory_sectors(); for (u32 sector : sectors) { bool done = false; - fsblk_t::block_t block = m_blockdev.get(sector); + fsblk_t::block_t::ptr block = m_blockdev.get(sector); for (u32 index = 0; !done && (index < dirents_per_sector()); index++) { directory_entry dirent(block, index * 32); - if (dirent.raw_stem()[0] != 0x00 && !dirent.is_deleted()) + if (dirent.raw_stem()[0] != 0x00 && !dirent.is_deleted() && !dirent.is_long_file_name()) { // get the filename std::string_view stem = trim_end_spaces(dirent.raw_stem()); @@ -815,6 +1333,12 @@ void pc_fat_image::enumerate_f(floppy_enumerator &fe) const fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 737280, "pc_fat_dsdd", "PC FAT 3.5\" dual-sided double density"); fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1474560, "pc_fat_dshd", "PC FAT 3.5\" dual-sided high density"); fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_35, floppy_image::DSED, 2949120, "pc_fat_dsed", "PC FAT 3.5\" dual-sided extra density"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::SSDD, 163840, "pc_fat_525ssdd_8", "PC FAT 5.25\" single-sided double density, 8 sectors/track"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::SSDD, 184320, "pc_fat_525ssdd", "PC FAT 5.25\" single-sided double density, 9 sectors/track"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::DSDD, 327680, "pc_fat_525dsdd_8", "PC FAT 5.25\" dual-sided double density, 8 sectors/track"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::DSDD, 368640, "pc_fat_525dsdd", "PC FAT 5.25\" dual-sided double density, 9 sectors/track"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::DSQD, 737280, "pc_fat_525dsqd", "PC FAT 5.25\" dual-sided quad density"); + fe.add(FLOPPY_PC_FORMAT, floppy_image::FF_525, floppy_image::DSHD, 1228800, "pc_fat_525dshd", "PC FAT 5.25\" dual-sided high density"); } diff --git a/src/lib/formats/fs_hp98x5.cpp b/src/lib/formats/fs_hp98x5.cpp index a8eb139ef7a..f070d01b30f 100644 --- a/src/lib/formats/fs_hp98x5.cpp +++ b/src/lib/formats/fs_hp98x5.cpp @@ -107,17 +107,17 @@ namespace { virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; - virtual err_t format(const meta_data &meta) override; + virtual std::error_condition format(const meta_data &meta) override; private: // Map of used/free sectors @@ -202,7 +202,7 @@ namespace { using dir_t = std::vector<entry>; - err_t parse_filename(const std::string& name, std::string& basename, int& bpr, u8& file_type) const; + std::error_condition parse_filename(const std::string& name, std::string& basename, int& bpr, u8& file_type) const; bool validate_filename(const std::string& s) const; void ensure_dir_loaded(); std::pair<dir_t, sect_map> decode_dir() const; @@ -323,10 +323,10 @@ meta_data hp98x5_impl::volume_metadata() return res; } -std::pair<err_t, meta_data> hp98x5_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> hp98x5_impl::metadata(const std::vector<std::string> &path) { if (path.size() != 1) { - return std::make_pair(ERR_NOT_FOUND, meta_data{}); + return std::make_pair(error::not_found, meta_data{}); } std::string basename; @@ -334,21 +334,21 @@ std::pair<err_t, meta_data> hp98x5_impl::metadata(const std::vector<std::string> u8 file_type; auto err = parse_filename(path.front(), basename, bpr, file_type); - if (err != ERR_OK) { - return std::make_pair(ERR_NOT_FOUND, meta_data{}); + if (err) { + return std::make_pair(error::not_found, meta_data{}); } ensure_dir_loaded(); auto it = scan_dir(m_dir, basename); if (it == m_dir.end()) { - return std::make_pair(ERR_NOT_FOUND, meta_data{}); + return std::make_pair(error::not_found, meta_data{}); } auto meta = get_metadata(*it); - return std::make_pair(ERR_OK, std::move(meta)); + return std::make_pair(std::error_condition(), std::move(meta)); } -std::pair<err_t, std::vector<dir_entry>> hp98x5_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> hp98x5_impl::directory_contents(const std::vector<std::string> &path) { if (path.empty()) { ensure_dir_loaded(); @@ -360,16 +360,16 @@ std::pair<err_t, std::vector<dir_entry>> hp98x5_impl::directory_contents(const s dir_entries.emplace_back(dir_entry_type::file, std::move(meta)); } } - return std::make_pair(ERR_OK, dir_entries); + return std::make_pair(std::error_condition(), dir_entries); } else { - return std::make_pair(ERR_NOT_FOUND, std::vector<dir_entry>{}); + return std::make_pair(error::not_found, std::vector<dir_entry>{}); } } -err_t hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) { if (!path.empty()) { - return ERR_INVALID; + return error::invalid_name; } auto name = meta.get_string(meta_name::name); @@ -381,9 +381,13 @@ err_t hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_ // Parse & validate filename // Extension must be specified auto err = parse_filename(name, basename, bpr, file_type); - if (err != ERR_OK || file_type == NO_FILE_TYPE) { - return ERR_INVALID; + if (err) { + return err; + } + if (file_type == NO_FILE_TYPE) { + return error::invalid_name; } + if (bpr < 0) { // Use default bpr when not specified bpr = DEF_BPR; @@ -393,7 +397,7 @@ err_t hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_ ensure_dir_loaded(); auto it = scan_dir(m_dir, basename); if (it != m_dir.end()) { - return ERR_INVALID; + return error::already_exists; } // Find a free entry in directory @@ -404,7 +408,7 @@ err_t hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_ m_dir.emplace_back(entry()); it2 = m_dir.end() - 1; } else { - return ERR_NO_SPACE; + return error::no_space; } } @@ -421,13 +425,13 @@ err_t hp98x5_impl::file_create(const std::vector<std::string> &path, const meta_ store_dir_map(); - return ERR_OK; + return std::error_condition(); } -std::pair<err_t, std::vector<u8>> hp98x5_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> hp98x5_impl::file_read(const std::vector<std::string> &path) { if (path.size() != 1) { - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>{}); + return std::make_pair(error::not_found, std::vector<u8>{}); } std::string basename; int bpr; @@ -435,10 +439,10 @@ std::pair<err_t, std::vector<u8>> hp98x5_impl::file_read(const std::vector<std:: auto err = parse_filename(path.front(), basename, bpr, file_type); - if (err == ERR_OK) { + if (!err) { auto it = find_file(basename, bpr, file_type); if (it == m_dir.end()) { - err = ERR_NOT_FOUND; + err = error::not_found; } else { auto file_data = get_sector_range(it->m_1st_sect, it->m_sectors); if (file_type == TEXT_TYPE) { @@ -446,16 +450,16 @@ std::pair<err_t, std::vector<u8>> hp98x5_impl::file_read(const std::vector<std:: } else { file_data.resize(it->m_size); } - return std::make_pair(ERR_OK, std::move(file_data)); + return std::make_pair(std::error_condition(), std::move(file_data)); } } return std::make_pair(err, std::vector<u8>{}); } -err_t hp98x5_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::error_condition hp98x5_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) { if (path.size() != 1) { - return ERR_NOT_FOUND; + return error::not_found; } std::string basename; @@ -463,13 +467,13 @@ err_t hp98x5_impl::file_write(const std::vector<std::string> &path, const std::v u8 file_type; auto err = parse_filename(path.front(), basename, bpr, file_type); - if (err != ERR_OK) { + if (err) { return err; } // Check that file already exists auto it = find_file(basename, bpr, file_type); if (it == m_dir.end()) { - return ERR_NOT_FOUND; + return error::not_found; } // De-allocate current blocks @@ -488,7 +492,7 @@ err_t hp98x5_impl::file_write(const std::vector<std::string> &path, const std::v // Allocate space it->m_sectors = (data_ptr->size() + SECTOR_SIZE - 1) / SECTOR_SIZE; if (!allocate(it->m_sectors, it->m_1st_sect)) { - return ERR_NO_SPACE; + return error::no_space; } // Store file content @@ -498,10 +502,10 @@ err_t hp98x5_impl::file_write(const std::vector<std::string> &path, const std::v // Update directory & map store_dir_map(); - return ERR_OK; + return std::error_condition(); } -err_t hp98x5_impl::format(const meta_data &meta) +std::error_condition hp98x5_impl::format(const meta_data &meta) { bool is_ds = m_blockdev.block_count() == DS_SECTORS; @@ -540,11 +544,11 @@ err_t hp98x5_impl::format(const meta_data &meta) // Interleave factor w16b(out_ins, m_fmt_interleave[ m_fs_type ]); - m_blockdev.get(0).copy(0, sys_rec.data(), sys_rec.size()); + m_blockdev.get(0)->write(0, sys_rec.data(), sys_rec.size()); // 9825 & 9831 have a backup copy of system record in spare track but 9845 hasn't, go figure if (m_fs_type != FS_TYPE_9845) { - m_blockdev.get(m_spare_start).copy(0, sys_rec.data(), sys_rec.size()); + m_blockdev.get(m_spare_start)->write(0, sys_rec.data(), sys_rec.size()); } m_dir.clear(); @@ -553,10 +557,10 @@ err_t hp98x5_impl::format(const meta_data &meta) store_dir_map(); - return ERR_OK; + return std::error_condition(); } -err_t hp98x5_impl::parse_filename(const std::string& name, std::string& basename, int& bpr, u8& file_type) const +std::error_condition hp98x5_impl::parse_filename(const std::string& name, std::string& basename, int& bpr, u8& file_type) const { // General form of filenames: // basename[[.&bpr].ext] @@ -579,18 +583,18 @@ err_t hp98x5_impl::parse_filename(const std::string& name, std::string& basename if (p2 != std::string::npos) { // [p1+1 p2) should have "&bpr" if (name[ p1 + 1 ] != '&') { - return ERR_INVALID; + return error::invalid_name; } if (!std::all_of(name.cbegin() + p1 + 2, name.cbegin() + p2, [](char c) { return c >= '0' && c <= '9'; })) { - return ERR_INVALID; + return error::invalid_name; } try { bpr = std::stoul(std::string{name, p1 + 2, p2 - p1 - 2}); } catch (...) { - return ERR_INVALID; + return error::invalid_name; } if (bpr < 4 || bpr > 32767 || (bpr & 1) != 0) { - return ERR_INVALID; + return error::invalid_name; } } else { p2 = p1; @@ -607,7 +611,7 @@ err_t hp98x5_impl::parse_filename(const std::string& name, std::string& basename } } if (file_type == NO_FILE_TYPE) { - return ERR_INVALID; + return error::invalid_name; } } } @@ -615,9 +619,9 @@ err_t hp98x5_impl::parse_filename(const std::string& name, std::string& basename // [0 p1) has "basename" basename = std::string(name, 0, p1); if (validate_filename(basename)) { - return ERR_OK; + return std::error_condition(); } else { - return ERR_INVALID; + return error::invalid_name; } } @@ -659,14 +663,14 @@ void hp98x5_impl::ensure_dir_loaded() // 8 Count of data tracks // 9 Interleave factor // 10..127 N/U - u16 sects_per_track = sys_rec.r16b(2); - u16 tot_tracks = sys_rec.r16b(4); - u16 spare_track = sys_rec.r16b(6); - u16 dir_start = sys_rec.r16b(8); - u16 av_start = sys_rec.r16b(10); - u16 av_end = sys_rec.r16b(12); - u16 sys_tracks = sys_rec.r16b(14); - u16 data_tracks = sys_rec.r16b(16); + u16 sects_per_track = sys_rec->r16b(2); + u16 tot_tracks = sys_rec->r16b(4); + u16 spare_track = sys_rec->r16b(6); + u16 dir_start = sys_rec->r16b(8); + u16 av_start = sys_rec->r16b(10); + u16 av_end = sys_rec->r16b(12); + u16 sys_tracks = sys_rec->r16b(14); + u16 data_tracks = sys_rec->r16b(16); m_img_tracks = m_blockdev.block_count() / SECTORS; @@ -1155,7 +1159,7 @@ std::vector<u8> hp98x5_impl::get_sector_range(lba_t first, unsigned size) const for (lba_t idx = first; idx < first + size; idx++) { auto data_sect = m_blockdev.get(u32(idx)); - memcpy(ptr, data_sect.rodata(), SECTOR_SIZE); + data_sect->read(0, ptr, SECTOR_SIZE); ptr += SECTOR_SIZE; } return res; @@ -1169,7 +1173,7 @@ void hp98x5_impl::store_sector_range(lba_t first, const std::vector<u8>& data) for (lba_t idx = first; idx < first + sects; idx++) { u32 count = std::min<u32>(to_go, SECTOR_SIZE); auto blk = m_blockdev.get(u32(idx)); - blk.copy(0, ptr, count); + blk->write(0, ptr, count); ptr += count; to_go -= count; } diff --git a/src/lib/formats/fs_hplif.cpp b/src/lib/formats/fs_hplif.cpp index 48dde255cb4..8a3d2c52da4 100644 --- a/src/lib/formats/fs_hplif.cpp +++ b/src/lib/formats/fs_hplif.cpp @@ -64,27 +64,27 @@ public: u8 size() const; private: - const impl & m_fs; - fsblk_t::block_t m_block; - u8 m_sector; - u32 m_sector_count; + const impl & m_fs; + fsblk_t::block_t::ptr m_block; + u8 m_sector; + u32 m_sector_count; }; impl(fsblk_t &blockdev); virtual ~impl() = default; virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; private: - fsblk_t::block_t read_sector(u32 starting_sector) const; + fsblk_t::block_t::ptr read_sector(u32 starting_sector) const; std::optional<hplif_dirent> dirent_from_path(const std::vector<std::string> &path) const; void iterate_directory_entries(const std::function<bool(const hplif_dirent &dirent)> &callback) const; util::arbitrary_datetime decode_datetime(const hplif_time *time) const; meta_data metadata_from_dirent(const hplif_dirent &dirent) const; - err_t format(const meta_data &meta) override; + std::error_condition format(const meta_data &meta) override; }; // methods @@ -120,10 +120,10 @@ const char *fs::hplif_image::description() const void fs::hplif_image::enumerate_f(floppy_enumerator &fe) const { - fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 630784, "hp_lif_9121_format_1", "HP 9212 LIF 3.5\" dual-sided double density Format 1"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 630784, "hp_lif_9121_format_1", "HP 9121 LIF 3.5\" dual-sided double density Format 1"); fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 709632, "hp_lif_9121_format_2", "HP 9121 LIF 3.5\" dual-sided double density Format 2"); fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 788480, "hp_lif_9121_format_3", "HP 9121 LIF 3.5\" dual-sided double density Format 3"); - fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::SSDD, 286720, "hp_lif_9121_format_4", "HP 9121 LIF 3.5\" single-sided double density Format 4"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::SSDD, 270336, "hp_lif_9121_format_4", "HP 9121 LIF 3.5\" single-sided double density Format 4"); fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 737280, "hp_lif_9121_format_16", "HP 9121 LIF 3.5\" dual-sided double density Format 16"); fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1261568, "hp_lif_9122_format_014", "HP 9122 LIF 3.5\" dual-sided high density Format 0, 1, 4"); @@ -252,11 +252,11 @@ impl::impl(fsblk_t &blockdev) meta_data impl::volume_metadata() { auto block = read_sector(0); - std::string_view disk_name = std::string_view((const char *) block.rodata() + 2, 6); + std::string_view disk_name = block->rstr(2, 6); meta_data results; results.set(meta_name::name, strtrimright_hplif(disk_name)); - results.set(meta_name::creation_date, decode_datetime(reinterpret_cast<const hplif_time *>(block.rodata() + 36))); + results.set(meta_name::creation_date, decode_datetime(reinterpret_cast<const hplif_time *>(block->rodata() + 36))); return results; } @@ -265,13 +265,13 @@ meta_data impl::volume_metadata() // impl::metadata //------------------------------------------------- -std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> impl::metadata(const std::vector<std::string> &path) { std::optional<hplif_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, metadata_from_dirent(*dirent)); + return std::make_pair(std::error_condition(), metadata_from_dirent(*dirent)); } @@ -279,7 +279,7 @@ std::pair<err_t, meta_data> impl::metadata(const std::vector<std::string> &path) // impl::directory_contents //------------------------------------------------- -std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> impl::directory_contents(const std::vector<std::string> &path) { std::vector<dir_entry> results; auto callback = [this, &results](const hplif_dirent &ent) @@ -288,7 +288,7 @@ std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vec return false; }; iterate_directory_entries(callback); - return std::make_pair(ERR_OK, std::move(results)); + return std::make_pair(std::error_condition(), std::move(results)); } @@ -296,12 +296,12 @@ std::pair<err_t, std::vector<dir_entry>> impl::directory_contents(const std::vec // impl::file_read //------------------------------------------------- -std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> impl::file_read(const std::vector<std::string> &path) { // find the file std::optional<hplif_dirent> dirent = dirent_from_path(path); if (!dirent) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); // and get the data u32 sector_count = big_endianize_int32(dirent->m_sector_count); @@ -316,7 +316,7 @@ std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> while (iter.next()) result.insert(result.end(), (const u8 *)iter.data(), (const u8 *)iter.data() + 256); - return std::make_pair(ERR_OK, std::move(result)); + return std::make_pair(std::error_condition(), std::move(result)); } @@ -324,7 +324,7 @@ std::pair<err_t, std::vector<u8>> impl::file_read(const std::vector<std::string> // impl::read_sector //------------------------------------------------- -fsblk_t::block_t impl::read_sector(u32 sector) const +fsblk_t::block_t::ptr impl::read_sector(u32 sector) const { return m_blockdev.get(sector); } @@ -359,10 +359,10 @@ std::optional<impl::hplif_dirent> impl::dirent_from_path(const std::vector<std:: void impl::iterate_directory_entries(const std::function<bool(const hplif_dirent &dirent)> &callback) const { - fsblk_t::block_t block = m_blockdev.get(0); - block_iterator iter(*this, block.r32b(8), block.r32b(16)); + fsblk_t::block_t::ptr block = m_blockdev.get(0); + block_iterator iter(*this, block->r32b(8), block->r32b(16)); - if (block.r16b(0) != 0x8000) + if (block->r16b(0) != 0x8000) { return; } @@ -461,30 +461,30 @@ bool impl::block_iterator::next() const void *impl::block_iterator::data() const { - return m_block.rodata(); + return m_block->rodata(); } //------------------------------------------------- // impl::format //------------------------------------------------- -err_t impl::format(const meta_data &meta) +std::error_condition impl::format(const meta_data &meta) { std::string volume_name = meta.get_string(meta_name::name, "B9826 "); - fsblk_t::block_t block = m_blockdev.get(0); + fsblk_t::block_t::ptr block = m_blockdev.get(0); if (volume_name.size() < 6) volume_name.insert(volume_name.end(), 6 - volume_name.size(), ' '); if (volume_name.size() > 6) volume_name.resize(6); - block.w16b(0, 0x8000); // LIF magic - block.wstr(2, volume_name); - block.w32b(8, 2); // directory start - block.w16b(12, 0x1000); // LIF identifier - block.w32b(16, 14); // directory size - block.w16b(20, 1); // LIF version - return ERR_OK; + block->w16b(0, 0x8000); // LIF magic + block->wstr(2, volume_name); + block->w32b(8, 2); // directory start + block->w16b(12, 0x1000); // LIF identifier + block->w32b(16, 14); // directory size + block->w16b(20, 1); // LIF version + return std::error_condition(); } //------------------------------------------------- @@ -493,7 +493,7 @@ err_t impl::format(const meta_data &meta) const std::array<impl::hplif_dirent, 8> &impl::block_iterator::dirent_data() const { - return *reinterpret_cast<const std::array<impl::hplif_dirent, 8> *>(m_block.rodata()); + return *reinterpret_cast<const std::array<impl::hplif_dirent, 8> *>(m_block->rodata()); } } // anonymous namespace diff --git a/src/lib/formats/fs_isis.cpp b/src/lib/formats/fs_isis.cpp index 3b79851522b..fb79314a360 100644 --- a/src/lib/formats/fs_isis.cpp +++ b/src/lib/formats/fs_isis.cpp @@ -45,17 +45,17 @@ namespace { virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; - virtual err_t format(const meta_data &meta) override; + virtual std::error_condition format(const meta_data &meta) override; private: using sect_map = std::bitset<DD_SECTORS>; @@ -225,24 +225,24 @@ meta_data isis_impl::volume_metadata() return res; } -std::pair<err_t, meta_data> isis_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> isis_impl::metadata(const std::vector<std::string> &path) { if (path.size() != 1) { - return std::make_pair(ERR_NOT_FOUND, meta_data{}); + return std::make_pair(error::not_found, meta_data{}); } ensure_dir_loaded(); auto it = scan_dir(path.front()); if (it == m_dir.end()) { - return std::make_pair(ERR_NOT_FOUND, meta_data{}); + return std::make_pair(error::not_found, meta_data{}); } auto meta = get_metadata(*it); - return std::make_pair(ERR_OK, std::move(meta)); + return std::make_pair(std::error_condition(), std::move(meta)); } -std::pair<err_t, std::vector<dir_entry>> isis_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> isis_impl::directory_contents(const std::vector<std::string> &path) { if (path.empty()) { ensure_dir_loaded(); @@ -254,16 +254,16 @@ std::pair<err_t, std::vector<dir_entry>> isis_impl::directory_contents(const std dir_entries.emplace_back(dir_entry_type::file, std::move(meta)); } } - return std::make_pair(ERR_OK, dir_entries); + return std::make_pair(std::error_condition(), dir_entries); } else { - return std::make_pair(ERR_NOT_FOUND, std::vector<dir_entry>{}); + return std::make_pair(error::not_found, std::vector<dir_entry>{}); } } -err_t isis_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition isis_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) { if (!path.empty()) { - return ERR_INVALID; + return error::invalid_name; } auto name = meta.get_string(meta_name::name); @@ -274,13 +274,13 @@ err_t isis_impl::file_create(const std::vector<std::string> &path, const meta_da std::string filename = name.substr(0, pt_pos); if (filename.size() < 1 || filename.size() > 6 || !validate_filename(filename)) { - return ERR_INVALID; + return error::invalid_name; } if (pt_pos != std::string::npos) { auto ext = name.substr(pt_pos + 1); if (ext.size() < 1 || ext.size() > 3 || !validate_filename(ext)) { - return ERR_INVALID; + return error::invalid_name; } filename.push_back('.'); filename += ext; @@ -288,14 +288,14 @@ err_t isis_impl::file_create(const std::vector<std::string> &path, const meta_da // Check that file can be created by user if (!user_can_create(filename)) { - return ERR_INVALID; + return error::unsupported; } // Check that file doesn't exist ensure_dir_loaded(); auto it = scan_dir(filename); if (it != m_dir.end()) { - return ERR_INVALID; + return error::already_exists; } // Find a free entry in directory @@ -305,13 +305,13 @@ err_t isis_impl::file_create(const std::vector<std::string> &path, const meta_da } } if (it == m_dir.end()) { - return ERR_NO_SPACE; + return error::no_space; } // Allocate space lba_list lbas; if (!allocate(0, lbas)) { - return ERR_NO_SPACE; + return error::no_space; } // Fill dir entry @@ -326,42 +326,42 @@ err_t isis_impl::file_create(const std::vector<std::string> &path, const meta_da // Update directory & map store_dir_map(); - return ERR_OK; + return std::error_condition(); } -std::pair<err_t, std::vector<u8>> isis_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> isis_impl::file_read(const std::vector<std::string> &path) { const auto& [ lbas, size ] = find_file(path); if (lbas != nullptr) { auto file_data = get_file_content(*lbas, size); - return std::make_pair(ERR_OK, std::move(file_data)); + return std::make_pair(std::error_condition(), std::move(file_data)); } - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>{}); + return std::make_pair(error::not_found, std::vector<u8>{}); } -err_t isis_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::error_condition isis_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) { if (path.size() != 1) { - return ERR_NOT_FOUND; + return error::not_found; } // Check that file is user-writeable const auto& filename = path.front(); if (!user_can_write(filename)) { - return ERR_INVALID; + return error::unsupported; } // ISIS.T0 can only be 2944 bytes long bool is_t0 = filename == ISIS_T0; if (is_t0 && data.size() != ISIS_T0_SIZE) { - return ERR_INVALID; + return error::incorrect_size; } // Check that file already exists ensure_dir_loaded(); auto it = scan_dir(filename); if (it == m_dir.end()) { - return ERR_NOT_FOUND; + return error::not_found; } // De-allocate current blocks @@ -372,7 +372,7 @@ err_t isis_impl::file_write(const std::vector<std::string> &path, const std::vec if (is_t0) { allocate_t0(lbas); } else if (!allocate(data.size(), lbas)) { - return ERR_NO_SPACE; + return error::no_space; } // Update dir entry @@ -386,10 +386,10 @@ err_t isis_impl::file_write(const std::vector<std::string> &path, const std::vec // Update directory & map store_dir_map(); - return ERR_OK; + return std::error_condition(); } -err_t isis_impl::format(const meta_data &meta) +std::error_condition isis_impl::format(const meta_data &meta) { entry dir_e; dir_e.m_alloc_state = DIR_IN_USE; @@ -442,7 +442,7 @@ err_t isis_impl::format(const meta_data &meta) } store_dir_map(); - return ERR_OK; + return std::error_condition(); } isis_impl::lba_t isis_impl::ts_2_lba(const track_sect &ts) const @@ -786,14 +786,14 @@ isis_impl::lba_list isis_impl::get_file_allocation(lba_t first_link, unsigned si res.push_back(curr_map); // Get a linkage block auto map_sect = m_blockdev.get(curr_map); - auto prev_ptr = lba_from_2b(map_sect , 0); - auto next_ptr = lba_from_2b(map_sect , 2); + auto prev_ptr = lba_from_2b(*map_sect , 0); + auto next_ptr = lba_from_2b(*map_sect , 2); if (prev_lba != prev_ptr) { throw std::runtime_error(util::string_format("Incorrect backward linking in sector %d", curr_map)); } // Scan all pointers in linkage block for (u32 i = 4; i < SECTOR_SIZE; i += 2) { - auto ptr = lba_from_2b(map_sect , i); + auto ptr = lba_from_2b(*map_sect , i); if (size > 0) { if (ptr < 0) { throw std::runtime_error(util::string_format("Unexpected end of pointer list in sector %d", curr_map)); @@ -839,7 +839,7 @@ std::vector<u8> isis_impl::get_file_content(const lba_list& sects, unsigned size if ((idx % (PTRS_PER_BLOCK + 1)) != 0) { unsigned to_copy = std::min(size, SECTOR_SIZE); auto data_sect = m_blockdev.get(sects[ idx ]); - memcpy(res.data() + pos, data_sect.rodata(), to_copy); + data_sect->read(0, res.data() + pos, to_copy); size -= to_copy; pos += to_copy; } @@ -856,7 +856,7 @@ void isis_impl::store_file_content(const lba_list& sects, const std::vector<u8>& lba_t link_lba = sects[ idx ]; auto blk = m_blockdev.get(link_lba); // Pointer to previous block - lba_to_2b(prev_ptr, blk, 0); + lba_to_2b(prev_ptr, *blk, 0); prev_ptr = link_lba; lba_t next_ptr; if (sects.size() - idx > (PTRS_PER_BLOCK + 1)) { @@ -867,10 +867,10 @@ void isis_impl::store_file_content(const lba_list& sects, const std::vector<u8>& next_ptr = -1; } // Pointer to next block - lba_to_2b(next_ptr, blk, 2); + lba_to_2b(next_ptr, *blk, 2); // Pointers to data blocks for (unsigned j = 0; j < PTRS_PER_BLOCK; j++) { - lba_to_2b((j + idx + 1 < sects.size()) ? sects[ j + idx + 1 ] : -1, blk, 4 + 2 * j); + lba_to_2b((j + idx + 1 < sects.size()) ? sects[ j + idx + 1 ] : -1, *blk, 4 + 2 * j); } } // Write data blocks @@ -883,7 +883,7 @@ void isis_impl::store_file_content(const lba_list& sects, const std::vector<u8>& } u32 count = std::min<u32>(to_go, SECTOR_SIZE); auto blk = m_blockdev.get(sects[ idx ]); - blk.copy(0, ptr, count); + blk->write(0, ptr, count); ptr += count; to_go -= count; } diff --git a/src/lib/formats/fs_oric_jasmin.cpp b/src/lib/formats/fs_oric_jasmin.cpp index 8cc79d917a1..db24a4a93f8 100644 --- a/src/lib/formats/fs_oric_jasmin.cpp +++ b/src/lib/formats/fs_oric_jasmin.cpp @@ -56,20 +56,20 @@ public: virtual ~oric_jasmin_impl() = default; virtual meta_data volume_metadata() override; - virtual err_t volume_metadata_change(const meta_data &info) override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual err_t metadata_change(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition volume_metadata_change(const meta_data &info) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::error_condition metadata_change(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual err_t rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) override; - virtual err_t remove(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::error_condition rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) override; + virtual std::error_condition remove(const std::vector<std::string> &path) override; - virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; - virtual err_t format(const meta_data &meta) override; + virtual std::error_condition format(const meta_data &meta) override; static bool validate_filename(std::string name); @@ -88,7 +88,7 @@ private: static std::string file_name_prepare(std::string name); static bool file_is_system(const u8 *entry); meta_data file_metadata(const u8 *entry); - std::tuple<fsblk_t::block_t, u32, bool> file_find(std::string name); + std::tuple<fsblk_t::block_t::ptr, u32, bool> file_find(std::string name); }; } @@ -196,40 +196,40 @@ bool oric_jasmin_impl::validate_filename(std::string name) return name.size() > 0 && name.size() <= 8; } -err_t oric_jasmin_impl::format(const meta_data &meta) +std::error_condition oric_jasmin_impl::format(const meta_data &meta) { std::string volume_name = meta.get_string(meta_name::name, "UNTITLED"); u32 blocks = m_blockdev.block_count(); - m_blockdev.fill(0x6c); + m_blockdev.fill_all(0x6c); u32 bblk = 20*17; auto fmap = m_blockdev.get(bblk); u32 off = 0; for(u32 blk = 0; blk != blocks; blk += 17) { if(blk == bblk) - fmap.w24l(off, 0x07fff); + fmap->w24l(off, 0x07fff); else - fmap.w24l(off, 0x1ffff); + fmap->w24l(off, 0x1ffff); off += 3; } for(u32 blk = blocks; blk != 17*42*2; blk += 17) { - fmap.w24l(off, 0x800000); + fmap->w24l(off, 0x800000); off += 3; } - fmap.w8(0xf6, 0x80); - fmap.w8(0xf7, 0x80); + fmap->w8(0xf6, 0x80); + fmap->w8(0xf7, 0x80); volume_name.resize(8, ' '); - fmap.wstr(0xf8, volume_name); + fmap->wstr(0xf8, volume_name); auto bdir = m_blockdev.get(20*17+1); - bdir.fill(0xff); - bdir.w16l(0, 0x0000); - bdir.w16l(2, 0x0000); + bdir->fill(0xff); + bdir->w16l(0, 0x0000); + bdir->w16l(2, 0x0000); - return ERR_OK; + return std::error_condition(); } meta_data oric_jasmin_impl::volume_metadata() @@ -237,21 +237,21 @@ meta_data oric_jasmin_impl::volume_metadata() meta_data res; auto bdir = m_blockdev.get(20*17); int len = 8; - while(len > 0 && bdir.rodata()[0xf8 + len - 1] == ' ') + while(len > 0 && bdir->rodata()[0xf8 + len - 1] == ' ') len--; - res.set(meta_name::name, bdir.rstr(0xf8, len)); + res.set(meta_name::name, bdir->rstr(0xf8, len)); return res; } -err_t oric_jasmin_impl::volume_metadata_change(const meta_data &meta) +std::error_condition oric_jasmin_impl::volume_metadata_change(const meta_data &meta) { if(meta.has(meta_name::name)) { std::string volume_name = meta.get_string(meta_name::name); volume_name.resize(8, ' '); - m_blockdev.get(20*17).wstr(0xf8, volume_name); + m_blockdev.get(20*17)->wstr(0xf8, volume_name); } - return ERR_OK; + return std::error_condition(); } std::string oric_jasmin_impl::file_name_prepare(std::string fname) @@ -315,28 +315,28 @@ meta_data oric_jasmin_impl::file_metadata(const u8 *entry) else { u16 ref = get_u16be(entry); auto dblk = m_blockdev.get(cs_to_block(ref)); - res.set(meta_name::loading_address, dblk.r16l(2)); - res.set(meta_name::length, dblk.r16l(4)); + res.set(meta_name::loading_address, dblk->r16l(2)); + res.set(meta_name::length, dblk->r16l(4)); } return res; } -std::tuple<fsblk_t::block_t, u32, bool> oric_jasmin_impl::file_find(std::string name) +std::tuple<fsblk_t::block_t::ptr, u32, bool> oric_jasmin_impl::file_find(std::string name) { name = file_name_prepare(name); auto bdir = m_blockdev.get(20*17+1); for(;;) { for(u32 i = 0; i != 14; i ++) { u32 off = 4 + i*18; - u16 fref = bdir.r16b(off); - if(ref_valid(fref) || file_is_system(bdir.rodata()+off)) { - if(memcmp(bdir.rodata() + off + 3, name.data(), 12)) { - bool sys = file_is_system(bdir.rodata() + off); + u16 fref = bdir->r16b(off); + if(ref_valid(fref) || file_is_system(bdir->rodata()+off)) { + if(memcmp(bdir->rodata() + off + 3, name.data(), 12)) { + bool sys = file_is_system(bdir->rodata() + off); return std::make_tuple(bdir, off, sys); } } } - u16 ref = bdir.r16b(2); + u16 ref = bdir->r16b(2); if(!ref || !ref_valid(ref)) return std::make_tuple(bdir, 0U, false); @@ -344,29 +344,29 @@ std::tuple<fsblk_t::block_t, u32, bool> oric_jasmin_impl::file_find(std::string } } -std::pair<err_t, meta_data> oric_jasmin_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> oric_jasmin_impl::metadata(const std::vector<std::string> &path) { if(path.size() != 1) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); auto [bdir, off, sys] = file_find(path[0]); std::ignore = sys; if(!off) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, file_metadata(bdir.rodata() + off)); + return std::make_pair(std::error_condition(), file_metadata(bdir->rodata() + off)); } -err_t oric_jasmin_impl::metadata_change(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition oric_jasmin_impl::metadata_change(const std::vector<std::string> &path, const meta_data &meta) { if(path.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off, sys] = file_find(path[0]); if(!off) - return ERR_NOT_FOUND; + return error::not_found; - u8 *entry = bdir.data() + off; + u8 *entry = bdir->data() + off; if(meta.has(meta_name::locked)) entry[0x02] = meta.get_flag(meta_name::locked) ? 'L' : 'U'; if(meta.has(meta_name::name)) @@ -374,33 +374,33 @@ err_t oric_jasmin_impl::metadata_change(const std::vector<std::string> &path, co if(meta.has(meta_name::sequential)) entry[0x0f] = meta.get_flag(meta_name::sequential) ? 'D' : 'S'; if(!sys && meta.has(meta_name::loading_address)) - m_blockdev.get(cs_to_block(get_u16be(entry))).w16l(2, meta.get_number(meta_name::loading_address)); + m_blockdev.get(cs_to_block(get_u16be(entry)))->w16l(2, meta.get_number(meta_name::loading_address)); - return ERR_OK; + return std::error_condition(); } -std::pair<err_t, std::vector<dir_entry>> oric_jasmin_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> oric_jasmin_impl::directory_contents(const std::vector<std::string> &path) { - std::pair<err_t, std::vector<dir_entry>> res; + std::pair<std::error_condition, std::vector<dir_entry>> res; if(path.size() != 0) { - res.first = ERR_NOT_FOUND; + res.first = error::not_found; return res; } - res.first = ERR_OK; + res.first = std::error_condition(); auto bdir = m_blockdev.get(20*17+1); for(;;) { for(u32 i = 0; i != 14; i ++) { u32 off = 4 + i*18; - u16 fref = bdir.r16b(off); - if(ref_valid(fref) || file_is_system(bdir.rodata()+off)) { - meta_data meta = file_metadata(bdir.rodata()+off); + u16 fref = bdir->r16b(off); + if(ref_valid(fref) || file_is_system(bdir->rodata()+off)) { + meta_data meta = file_metadata(bdir->rodata()+off); res.second.emplace_back(dir_entry(dir_entry_type::file, meta)); } } - u16 ref = bdir.r16b(2); + u16 ref = bdir->r16b(2); if(!ref || !ref_valid(ref)) break; bdir = m_blockdev.get(cs_to_block(ref)); @@ -408,30 +408,30 @@ std::pair<err_t, std::vector<dir_entry>> oric_jasmin_impl::directory_contents(co return res; } -err_t oric_jasmin_impl::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) +std::error_condition oric_jasmin_impl::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) { if(opath.size() != 1 || npath.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off, sys] = file_find(opath[0]); std::ignore = sys; if(!off) - return ERR_NOT_FOUND; + return error::not_found; - wstr(bdir.data() + off + 0x03, file_name_prepare(npath[0])); + wstr(bdir->data() + off + 0x03, file_name_prepare(npath[0])); - return ERR_OK; + return std::error_condition(); } -err_t oric_jasmin_impl::remove(const std::vector<std::string> &path) +std::error_condition oric_jasmin_impl::remove(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return error::unsupported; } -err_t oric_jasmin_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition oric_jasmin_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) { if(path.size() != 0) - return ERR_NOT_FOUND; + return error::not_found; // One block of sector list, one block of data u32 nb = 2; @@ -442,12 +442,12 @@ err_t oric_jasmin_impl::file_create(const std::vector<std::string> &path, const for(;;) { for(u32 i = 0; i != 14; i ++) { u32 off = 4 + i*18; - u16 ref = bdir.r16b(off); + u16 ref = bdir->r16b(off); if(!ref_valid(ref)) goto found; id++; } - u16 ref = bdir.r16b(2); + u16 ref = bdir->r16b(2); if(!ref || !ref_valid(ref)) { nb ++; break; @@ -457,68 +457,68 @@ err_t oric_jasmin_impl::file_create(const std::vector<std::string> &path, const found: auto block = allocate_blocks(nb); if(block.empty()) - return ERR_NO_SPACE; + return error::no_space; auto sblk = m_blockdev.get(cs_to_block(block[0])); - sblk.w16b(0, 0xff00); // Next sector - sblk.w16l(2, meta.get_number(meta_name::loading_address, 0x500)); - sblk.w16l(4, 0); // Length - sblk.w16b(6, block[1]); // Data block + sblk->w16b(0, 0xff00); // Next sector + sblk->w16l(2, meta.get_number(meta_name::loading_address, 0x500)); + sblk->w16l(4, 0); // Length + sblk->w16b(6, block[1]); // Data block if(nb == 3) { - bdir.w16l(0, block[2]); // Link to the next directory sector + bdir->w16l(0, block[2]); // Link to the next directory sector bdir = m_blockdev.get(cs_to_block(block[2])); - bdir.fill(0xff); - bdir.w16l(0, block[2]); // Reference to itself - bdir.w16l(2, 0xff00); // No next directory sector + bdir->fill(0xff); + bdir->w16l(0, block[2]); // Reference to itself + bdir->w16l(2, 0xff00); // No next directory sector } u32 off = 4 + (id % 14) * 18; - bdir.w16b(off+0x00, block[0]); // First (and only) sector in the sector list - bdir.w8 (off+0x02, meta.get_flag(meta_name::locked, false) ? 'L' : 'U'); - bdir.wstr(off+0x03, file_name_prepare(meta.get_string(meta_name::name, ""))); - bdir.w8 (off+0x0f, meta.get_flag(meta_name::sequential, true) ? 'S' : 'D'); - bdir.w16l(off+0x10, 2); // 2 sectors for an empty file + bdir->w16b(off+0x00, block[0]); // First (and only) sector in the sector list + bdir->w8 (off+0x02, meta.get_flag(meta_name::locked, false) ? 'L' : 'U'); + bdir->wstr(off+0x03, file_name_prepare(meta.get_string(meta_name::name, ""))); + bdir->w8 (off+0x0f, meta.get_flag(meta_name::sequential, true) ? 'S' : 'D'); + bdir->w16l(off+0x10, 2); // 2 sectors for an empty file - return ERR_OK; + return std::error_condition(); } -std::pair<err_t, std::vector<u8>> oric_jasmin_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> oric_jasmin_impl::file_read(const std::vector<std::string> &path) { std::vector<u8> data; if(path.size() != 1) - return std::make_pair(ERR_NOT_FOUND, data); + return std::make_pair(error::not_found, data); auto [bdir, off, sys] = file_find(path[0]); if(!off) - return std::make_pair(ERR_NOT_FOUND, data); + return std::make_pair(error::not_found, data); if(sys) { data.resize(0x3e00); for(u32 i = 0; i != 62; i++) { auto dblk = m_blockdev.get(i); - memcpy(data.data() + 256 * i, dblk.rodata(), 256); + dblk->read(0, data.data() + 256 * i, 256); } } else { - const u8 *entry = bdir.rodata() + off; + const u8 *entry = bdir->rodata() + off; u16 ref = get_u16be(entry); auto iblk = m_blockdev.get(cs_to_block(ref)); - u32 length = iblk.r16l(4); + u32 length = iblk->r16l(4); while(ref_valid(ref)) { for(u32 pos = 6; pos != 256 && data.size() < length; pos += 2) { - u16 dref = iblk.r16b(pos); + u16 dref = iblk->r16b(pos); if(!ref_valid(dref)) goto done; auto dblk = m_blockdev.get(cs_to_block(dref)); u32 dpos = data.size(); data.resize(dpos + 256); - memcpy(data.data() + dpos, dblk.rodata(), 256); + dblk->read(0, data.data() + dpos, 256); if(data.size() >= length) goto done; } - ref = iblk.r16b(2); + ref = iblk->r16b(2); if(!ref_valid(ref)) break; iblk = m_blockdev.get(cs_to_block(ref)); @@ -527,27 +527,27 @@ std::pair<err_t, std::vector<u8>> oric_jasmin_impl::file_read(const std::vector< data.resize(length); } - return std::make_pair(ERR_OK, data); + return std::make_pair(std::error_condition(), data); } -err_t oric_jasmin_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::error_condition oric_jasmin_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) { if(path.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off, sys] = file_find(path[0]); if(!off) - return ERR_NOT_FOUND; + return error::not_found; if(sys) { if(data.size() != 0x3e00) - return ERR_INVALID; + return error::incorrect_size; for(u32 i=0; i != 0x3e; i++) - m_blockdev.get(i).copy(0, data.data() + i * 256, 256); + m_blockdev.get(i)->write(0, data.data() + i * 256, 256); } else { - u8 *entry = bdir.data() + off; + u8 *entry = bdir->data() + off; u32 cur_ns = get_u16le(entry + 0x10); // Data sectors first u32 need_ns = (data.size() + 255) / 256; @@ -558,7 +558,7 @@ err_t oric_jasmin_impl::file_write(const std::vector<std::string> &path, const s // Enough space? if(cur_ns < need_ns && free_block_count() < need_ns - cur_ns) - return ERR_NO_SPACE; + return error::no_space; u16 load_address = 0; std::vector<u16> tofree; @@ -566,44 +566,44 @@ err_t oric_jasmin_impl::file_write(const std::vector<std::string> &path, const s for(u32 i=0; i < cur_ns; i += 125+1) { auto iblk = m_blockdev.get(cs_to_block(iref)); if(!i) - load_address = iblk.r16l(2); + load_address = iblk->r16l(2); tofree.push_back(iref); for(u32 j=0; j != 125 && i+j+1 != cur_ns; j++) - tofree.push_back(iblk.r16b(6+2*j)); - iref = iblk.r16b(2); + tofree.push_back(iblk->r16b(6+2*j)); + iref = iblk->r16b(2); } free_blocks(tofree); std::vector<u16> blocks = allocate_blocks(need_ns); for(u32 i=0; i < need_ns; i += 125+1) { auto iblk = m_blockdev.get(cs_to_block(blocks[i])); - iblk.fill(0xff); + iblk->fill(0xff); if(!i) { - iblk.w16l(2, load_address); - iblk.w16l(4, data.size()); + iblk->w16l(2, load_address); + iblk->w16l(4, data.size()); } if(i + 126 < need_ns) - iblk.w16b(0, blocks[i+126]); + iblk->w16b(0, blocks[i+126]); else - iblk.w16b(0, 0xff00); + iblk->w16b(0, 0xff00); for(u32 j=0; j != 125 && i+j+1 != need_ns; j++) { u32 dpos = 256 * (j + i/126*125); u32 size = data.size() - dpos; - iblk.w16b(6+j*2, blocks[i+j+1]); + iblk->w16b(6+j*2, blocks[i+j+1]); auto dblk = m_blockdev.get(cs_to_block(blocks[i+j+1])); if(size >= 256) - dblk.copy(0, data.data() + dpos, 256); + dblk->write(0, data.data() + dpos, 256); else { - dblk.copy(0, data.data() + dpos, size); - dblk.fill(size, 0x55, 256-size); + dblk->write(0, data.data() + dpos, size); + dblk->fill(size, 0x55, 256-size); } } } put_u16le(entry + 0x10, need_ns); put_u16be(entry + 0x00, blocks[0]); } - return ERR_OK; + return std::error_condition(); } std::vector<u16> oric_jasmin_impl::allocate_blocks(u32 count) @@ -615,7 +615,7 @@ std::vector<u16> oric_jasmin_impl::allocate_blocks(u32 count) auto fmap = m_blockdev.get(20*17); u32 nf = 0; for(u32 track = 0; track != 2*41 && nf != count; track++) { - u32 map = fmap.r24l(track*3); + u32 map = fmap->r24l(track*3); if(map != 0x800000) { for(u32 sect = 1; sect <= 17 && nf != count; sect++) if(map & (0x20000 >> sect)) { @@ -625,7 +625,7 @@ std::vector<u16> oric_jasmin_impl::allocate_blocks(u32 count) } if(!map) map = 0x800000; - fmap.w24l(track*3, map); + fmap->w24l(track*3, map); } } return blocks; @@ -637,11 +637,11 @@ void oric_jasmin_impl::free_blocks(const std::vector<u16> &blocks) for(u16 ref : blocks) { u32 track = ref >> 8; u32 sect = ref & 0xff; - u32 map = fmap.r24l(track*3); + u32 map = fmap->r24l(track*3); if(map == 0x800000) map = 0; map |= 0x20000 >> sect; - fmap.w24l(track*3, map); + fmap->w24l(track*3, map); } } @@ -650,7 +650,7 @@ u32 oric_jasmin_impl::free_block_count() auto fmap = m_blockdev.get(20*17); u32 nf = 0; for(u32 track = 0; track != 2*41; track++) { - u32 map = fmap.r24l(track*3); + u32 map = fmap->r24l(track*3); if(map != 0x800000) { for(u32 sect = 1; sect <= 17; sect++) if(map & (0x20000 >> sect)) diff --git a/src/lib/formats/fs_prodos.cpp b/src/lib/formats/fs_prodos.cpp index 826aecec91f..f7c77d47ff8 100644 --- a/src/lib/formats/fs_prodos.cpp +++ b/src/lib/formats/fs_prodos.cpp @@ -5,11 +5,14 @@ #include "fs_prodos.h" #include "ap_dsk35.h" +#include "ap2_dsk.h" #include "fsblk.h" +#include "corestr.h" #include "multibyte.h" #include "strformat.h" +#include <map> #include <stdexcept> using namespace fs; @@ -23,22 +26,22 @@ public: virtual ~prodos_impl() = default; virtual meta_data volume_metadata() override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual std::pair<err_t, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path) override; - virtual err_t format(const meta_data &meta) override; + virtual std::error_condition format(const meta_data &meta) override; private: static const u8 boot[512]; static util::arbitrary_datetime prodos_to_dt(u32 date); - std::tuple<fsblk_t::block_t, u32> path_find_step(const std::string &name, u16 block); - std::tuple<fsblk_t::block_t, u32, bool> path_find(const std::vector<std::string> &path); - std::pair<err_t, std::vector<u8>> any_read(u8 type, u16 block, u32 length); + std::tuple<fsblk_t::block_t::ptr, u32> path_find_step(const std::string &name, u16 block); + std::tuple<fsblk_t::block_t::ptr, u32, bool> path_find(const std::vector<std::string> &path); + std::pair<std::error_condition, std::vector<u8>> any_read(u8 type, u16 block, u32 length); }; } @@ -90,8 +93,9 @@ const u8 prodos_impl::boot[512] = { void prodos_image::enumerate_f(floppy_enumerator &fe) const { - fe.add(FLOPPY_APPLE_GCR_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 819200, "prodos_800k", "Apple ProDOS 800K"); - fe.add(FLOPPY_APPLE_GCR_FORMAT, floppy_image::FF_35, floppy_image::SSDD, 409600, "prodos_400k", "Apple ProDOS 400K"); + fe.add(FLOPPY_APPLE_GCR_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 819200, "prodos_800k", "Apple ProDOS 3.5\" 800K"); + fe.add(FLOPPY_APPLE_GCR_FORMAT, floppy_image::FF_35, floppy_image::SSDD, 409600, "prodos_400k", "Apple ProDOS 3.5\" 400K"); + fe.add(FLOPPY_A216S_PRODOS_FORMAT, floppy_image::FF_525, floppy_image::SSSD, 143360, "prodos_140k", "Apple ProDOS 5.25\" 140K"); } std::unique_ptr<filesystem_t> prodos_image::mount(fsblk_t &blockdev) const @@ -124,6 +128,46 @@ char prodos_image::directory_separator() const return '/'; } +// TODO: this list is incomplete +static const std::map<u8, const char *> s_file_types = +{ + { 0x00, "UNK" }, + { 0x01, "BAD" }, + { 0x04, "TXT" }, + { 0x06, "BIN" }, + { 0x0f, "DIR" }, + { 0x19, "ADB" }, + { 0x1a, "AWP" }, + { 0x1b, "ASP" }, + { 0xc9, "FND" }, + { 0xca, "ICN" }, + { 0xef, "PAS" }, + { 0xf0, "CMD" }, + { 0xfa, "INT" }, + { 0xfb, "IVR" }, + { 0xfc, "BAS" }, + { 0xfd, "VAR" }, + { 0xfe, "REL" }, + { 0xff, "SYS" } +}; + +static std::string file_type_to_string(uint8_t type) +{ + auto res = s_file_types.find(type); + if (res != s_file_types.end()) + return res->second; + else + return util::string_format("0x%02x", type); +} + +static bool validate_file_type(std::string str) +{ + if ((str.length() == 3 || str.length() == 4) && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + return str.find_first_not_of("0123456789ABCDEFabcdef", 2) == std::string::npos; + else + return std::any_of(s_file_types.begin(), s_file_types.end(), [&str](const auto &pair) { return util::strequpper(str, pair.second); }); +} + std::vector<meta_description> prodos_image::volume_meta_description() const { std::vector<meta_description> res; @@ -143,6 +187,7 @@ std::vector<meta_description> prodos_image::file_meta_description() const res.emplace_back(meta_description(meta_name::name, "Empty file", false, [](const meta_value &m) { return m.as_string().size() <= 15; }, "File name, up to 15 characters")); res.emplace_back(meta_description(meta_name::length, 0, true, nullptr, "Size of the file in bytes")); res.emplace_back(meta_description(meta_name::rsrc_length, 0, true, nullptr, "Size of the resource fork in bytes")); + res.emplace_back(meta_description(meta_name::file_type, "UNK", false, [](const meta_value &m) { return validate_file_type(m.as_string()); }, "File type, 3 letters or hex code preceded by 0x")); res.emplace_back(meta_description(meta_name::os_version, 5, false, [](const meta_value &m) { return m.as_number() <= 255; }, "Creator OS version")); res.emplace_back(meta_description(meta_name::os_minimum_version, 5, false, [](const meta_value &m) { return m.as_number() <= 255; }, "Minimum OS version")); @@ -165,7 +210,7 @@ std::vector<meta_description> prodos_image::directory_meta_description() const return res; } -err_t prodos_impl::format(const meta_data &meta) +std::error_condition prodos_impl::format(const meta_data &meta) { std::string volume_name = meta.get_string(meta_name::name, "UNTITLED"); u32 blocks = m_blockdev.block_count(); @@ -174,36 +219,36 @@ err_t prodos_impl::format(const meta_data &meta) if(blocks >= 0x10000) blocks = 0xffff; - m_blockdev.get(0).copy(0x000, boot, 0x200); // Standard ProDOS boot sector as written by a 2gs - m_blockdev.get(1).fill(0x00); // No SOS boot sector + m_blockdev.get(0)->write(0x000, boot, 0x200); // Standard ProDOS boot sector as written by a 2gs + m_blockdev.get(1)->fill(0x00); // No SOS boot sector auto kblk1 = m_blockdev.get(2); // key block first block auto kblk2 = m_blockdev.get(3); // key block second block auto kblk3 = m_blockdev.get(4); // key block third block auto kblk4 = m_blockdev.get(5); // key block fourth block - kblk1.w16l(0x00, 0x0000); // Backwards key block pointer (null) - kblk1.w16l(0x02, 0x0003); // Forwards key block pointer - kblk1.w8 (0x04, 0xf0 | volume_name.size()); // Block type (f, key block) and name size - kblk1.wstr(0x05, volume_name); // Volume name, up to 15 characters - kblk1.w32b(0x16, 0x642a250d); // ??? date & time - kblk1.w16b(0x1a, 0x80ff); // ??? - kblk1.w32b(0x1c, 0x642a250d); // Creation date & time - kblk1.w8 (0x20, 0x05); // ProDOS version (2gs) - kblk1.w8 (0x21, 0x00); // ProDOS minimum version - kblk1.w8 (0x22, 0xc3); // Allowed access (destroy, rename, !backup, 3x0, write read) - kblk1.w8 (0x23, 0x27); // Directory entry length (fixed) - kblk1.w8 (0x24, 0x0d); // Entries per block (fixed) - kblk1.w16l(0x25, 0x0000); // Number of file entries in the directory - kblk1.w16l(0x27, 0x0006); // Bitmap block pointer - kblk1.w16l(0x29, blocks); // Number of blocks - - kblk2.w16l(0x00, 0x0002); // Backwards block pointer of the second volume block - kblk2.w16l(0x02, 0x0004); // Forwards block pointer of the second volume block - kblk3.w16l(0x00, 0x0003); // Backwards block pointer of the third volume block - kblk3.w16l(0x02, 0x0005); // Forwards block pointer of the third volume block - kblk4.w16l(0x00, 0x0004); // Backwards block pointer of the fourth volume block - kblk4.w16l(0x02, 0x0000); // Forwards block pointer of the fourth volume block (null) + kblk1->w16l(0x00, 0x0000); // Backwards key block pointer (null) + kblk1->w16l(0x02, 0x0003); // Forwards key block pointer + kblk1->w8 (0x04, 0xf0 | volume_name.size()); // Block type (f, key block) and name size + kblk1->wstr(0x05, volume_name); // Volume name, up to 15 characters + kblk1->w32b(0x16, 0x642a250d); // ??? date & time + kblk1->w16b(0x1a, 0x80ff); // ??? + kblk1->w32b(0x1c, 0x642a250d); // Creation date & time + kblk1->w8 (0x20, 0x05); // ProDOS version (2gs) + kblk1->w8 (0x21, 0x00); // ProDOS minimum version + kblk1->w8 (0x22, 0xc3); // Allowed access (destroy, rename, !backup, 3x0, write read) + kblk1->w8 (0x23, 0x27); // Directory entry length (fixed) + kblk1->w8 (0x24, 0x0d); // Entries per block (fixed) + kblk1->w16l(0x25, 0x0000); // Number of file entries in the directory + kblk1->w16l(0x27, 0x0006); // Bitmap block pointer + kblk1->w16l(0x29, blocks); // Number of blocks + + kblk2->w16l(0x00, 0x0002); // Backwards block pointer of the second volume block + kblk2->w16l(0x02, 0x0004); // Forwards block pointer of the second volume block + kblk3->w16l(0x00, 0x0003); // Backwards block pointer of the third volume block + kblk3->w16l(0x02, 0x0005); // Forwards block pointer of the third volume block + kblk4->w16l(0x00, 0x0004); // Backwards block pointer of the fourth volume block + kblk4->w16l(0x02, 0x0000); // Forwards block pointer of the fourth volume block (null) u32 fmap_block_count = (blocks + 4095) / 4096; u32 first_free_block = 6 + fmap_block_count; @@ -211,7 +256,7 @@ err_t prodos_impl::format(const meta_data &meta) // Mark blocks from first_free_block to blocks-1 (the last one) as free for(u32 i = 0; i != fmap_block_count; i++) { auto fmap = m_blockdev.get(6 + i); - u8 *fdata = fmap.data(); + u8 *fdata = fmap->data(); u32 start = i ? 0 : first_free_block; u32 end = i != fmap_block_count - 1 ? 4095 : (blocks - 1) & 4095; end += 1; @@ -229,7 +274,7 @@ err_t prodos_impl::format(const meta_data &meta) memset(fdata+sb, 0xff, eb-sb-1); } } - return ERR_OK; + return std::error_condition(); } prodos_impl::prodos_impl(fsblk_t &blockdev) : filesystem_t(blockdev, 512) @@ -242,8 +287,8 @@ util::arbitrary_datetime prodos_impl::prodos_to_dt(u32 date) dt.second = 0; dt.minute = ((date >> 16) & 0x3f); dt.hour = ((date >> 24) & 0x1f); - dt.day_of_month = ((date >> 0) & 0x1f); - dt.month = ((date >> 5) & 0x0f) + 1; + dt.day_of_month = ((date >> 0) & 0x1f); // 1-based + dt.month = ((date >> 5) & 0x0f); // 1-based dt.year = ((date >> 9) & 0x7f) + 1900; if (dt.year <= 1949) dt.year += 100; @@ -255,16 +300,16 @@ meta_data prodos_impl::volume_metadata() { meta_data res; auto bdir = m_blockdev.get(2); - int len = bdir.r8(0x04) & 0xf; - res.set(meta_name::name, bdir.rstr(0x05, len)); - res.set(meta_name::os_version, bdir.r8(0x20)); - res.set(meta_name::os_minimum_version, bdir.r8(0x21)); - res.set(meta_name::creation_date, prodos_to_dt(bdir.r32l(0x1c))); - res.set(meta_name::modification_date, prodos_to_dt(bdir.r32l(0x16))); + int len = bdir->r8(0x04) & 0xf; + res.set(meta_name::name, bdir->rstr(0x05, len)); + res.set(meta_name::os_version, bdir->r8(0x20)); + res.set(meta_name::os_minimum_version, bdir->r8(0x21)); + res.set(meta_name::creation_date, prodos_to_dt(bdir->r32l(0x1c))); + res.set(meta_name::modification_date, prodos_to_dt(bdir->r32l(0x16))); return res; } -std::pair<err_t, std::vector<dir_entry>> prodos_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> prodos_impl::directory_contents(const std::vector<std::string> &path) { u16 block; if(path.empty()) @@ -273,62 +318,66 @@ std::pair<err_t, std::vector<dir_entry>> prodos_impl::directory_contents(const s else { auto [blk, off, dir] = path_find(path); if(!off || !dir) - return std::make_pair(ERR_NOT_FOUND, std::vector<dir_entry>()); - block = blk.r16l(off+0x11); + return std::make_pair(error::not_found, std::vector<dir_entry>()); + block = blk->r16l(off+0x11); } std::vector<dir_entry> res; - u32 off = 39 + 4; do { auto blk = m_blockdev.get(block); - while(off < 511) { - meta_data meta; - u8 type = blk.r8(off); - meta.set(meta_name::name, blk.rstr(off+1, type & 0xf)); - type >>= 4; - - if(type == 5) { - auto rootblk = m_blockdev.get(blk.r16l(off+0x11)); - meta.set(meta_name::length, rootblk.r24l(0x005)); - meta.set(meta_name::rsrc_length, rootblk.r24l(0x105)); - - } else if(type >= 1 && type <= 3) - meta.set(meta_name::length, blk.r24l(off + 0x15)); - - res.emplace_back(dir_entry(type == 0xd ? dir_entry_type::dir : dir_entry_type::file, meta)); - off += 39; + for(u32 off = 4; off < 511; off += 39) { + u8 type = blk->r8(off); + // skip inactive entries and subroutine/volume headers + if(type != 0 && type < 0xe0) { + meta_data meta; + meta.set(meta_name::name, blk->rstr(off+1, type & 0xf)); + type >>= 4; + + if(type == 5) { + auto rootblk = m_blockdev.get(blk->r16l(off+0x11)); + meta.set(meta_name::length, rootblk->r24l(0x005)); + meta.set(meta_name::rsrc_length, rootblk->r24l(0x105)); + + } else if(type >= 1 && type <= 3) { + meta.set(meta_name::length, blk->r24l(off + 0x15)); + meta.set(meta_name::file_type, file_type_to_string(blk->r8(off + 0x10))); + } + + meta.set(meta_name::os_version, blk->r8(off + 0x1c)); + meta.set(meta_name::os_minimum_version, blk->r8(off + 0x1d)); + meta.set(meta_name::creation_date, prodos_to_dt(blk->r32l(off + 0x18))); + meta.set(meta_name::modification_date, prodos_to_dt(blk->r32l(off + 0x21))); + + res.emplace_back(dir_entry(type == 0xd ? dir_entry_type::dir : dir_entry_type::file, meta)); + } } - block = blk.r16l(2); + block = blk->r16l(2); if(block >= m_blockdev.block_count()) break; - off = 4; } while(block); - return std::make_pair(ERR_OK, res); + return std::make_pair(std::error_condition(), res); } -std::tuple<fsblk_t::block_t, u32> prodos_impl::path_find_step(const std::string &name, u16 block) +std::tuple<fsblk_t::block_t::ptr, u32> prodos_impl::path_find_step(const std::string &name, u16 block) { - u32 off = 39 + 4; for(;;) { auto blk = m_blockdev.get(block); - while(off < 511) { - u8 type = blk.r8(off); - if(name == blk.rstr(off+1, type & 0xf)) + for(u32 off = 4; off < 511; off += 39) { + u8 type = blk->r8(off); + if(type != 0 && type < 0xe0 && name == blk->rstr(off+1, type & 0xf)) return std::make_tuple(blk, off); - off += 39; } - block = blk.r16l(2); + block = blk->r16l(2); if(!block || block >= m_blockdev.block_count()) return std::make_tuple(blk, 0U); - off = 4; } } -std::tuple<fsblk_t::block_t, u32, bool> prodos_impl::path_find(const std::vector<std::string> &path) +std::tuple<fsblk_t::block_t::ptr, u32, bool> prodos_impl::path_find(const std::vector<std::string> &path) { if(path.size() == 0) - return std::tuple<fsblk_t::block_t, u32, bool>(fsblk_t::block_t(), 0, false); + return std::tuple<fsblk_t::block_t::ptr, u32, bool>(fsblk_t::block_t::ptr(), 0, false); u16 block = 2; for(u32 pathc = 0;; pathc++) { @@ -337,27 +386,27 @@ std::tuple<fsblk_t::block_t, u32, bool> prodos_impl::path_find(const std::vector return std::make_tuple(blk, off, false); if(pathc + 1 == path.size()) - return std::make_tuple(blk, off, (blk.r8(off) & 0xf0) == 0xd0); + return std::make_tuple(blk, off, (blk->r8(off) & 0xf0) == 0xd0); - if((blk.r8(off) & 0xf0) != 0xd0) + if((blk->r8(off) & 0xf0) != 0xd0) return std::make_tuple(blk, 0U, false); - block = blk.r16l(off + 0x11); + block = blk->r16l(off + 0x11); } } -std::pair<err_t, meta_data> prodos_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> prodos_impl::metadata(const std::vector<std::string> &path) { if(path.size() == 0) - return std::make_pair(ERR_OK, meta_data()); + return std::make_pair(std::error_condition(), meta_data()); auto [blk, off, dir] = path_find(path); if(!off) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - const u8 *entry = blk.rodata() + off; + const u8 *entry = blk->rodata() + off; meta_data res; if(dir) { @@ -371,23 +420,23 @@ std::pair<err_t, meta_data> prodos_impl::metadata(const std::vector<std::string> res.set(meta_name::name, name); if(type == 5) { auto rootblk = m_blockdev.get(get_u16le(entry+0x11)); - res.set(meta_name::length, rootblk.r24l(0x005)); - res.set(meta_name::rsrc_length, rootblk.r24l(0x105)); + res.set(meta_name::length, rootblk->r24l(0x005)); + res.set(meta_name::rsrc_length, rootblk->r24l(0x105)); } else if(type >= 1 && type <= 3) res.set(meta_name::length, get_u24le(entry + 0x15)); else - return std::make_pair(ERR_UNSUPPORTED, meta_data()); + return std::make_pair(error::unsupported, meta_data()); } - return std::make_pair(ERR_OK, res); + return std::make_pair(std::error_condition(), res); } -std::pair<err_t, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 length) +std::pair<std::error_condition, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 length) { - std::pair<err_t, std::vector<u8>> data; - data.first = ERR_OK; + std::pair<std::error_condition, std::vector<u8>> data; + data.first = std::error_condition(); data.second.resize((length + 511) & ~511); u32 nb = data.second.size()/512; if(!nb) @@ -397,15 +446,15 @@ std::pair<err_t, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 u8 *end = dst + data.second.size(); switch(type) { case 1: - memcpy(dst, m_blockdev.get(block).rodata(), 512); + m_blockdev.get(block)->read(0, dst, 512); dst += 512; break; case 2: { auto iblk = m_blockdev.get(block); for(u32 i=0; i != 256 && dst != end; i++) { - u16 blk = iblk.r8(i) | (iblk.r8(i | 0x100) << 8); - memcpy(dst, m_blockdev.get(blk).rodata(), 512); + u16 blk = iblk->r8(i) | (iblk->r8(i | 0x100) << 8); + m_blockdev.get(blk)->read(0, dst, 512); dst += 512; } break; @@ -415,10 +464,10 @@ std::pair<err_t, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 auto mblk = m_blockdev.get(block); for(u32 j=0; dst != end; j += 256) { u32 idx = j/256; - auto iblk = m_blockdev.get(mblk.r8(idx) | (mblk.r8(idx | 0x100) << 8)); + auto iblk = m_blockdev.get(mblk->r8(idx) | (mblk->r8(idx | 0x100) << 8)); for(u32 i=0; i != 256 && dst != end; i++) { - u16 blk = iblk.r8(i) | (iblk.r8(i | 0x100) << 8); - memcpy(dst, m_blockdev.get(blk).rodata(), 512); + u16 blk = iblk->r8(i) | (iblk->r8(i | 0x100) << 8); + m_blockdev.get(blk)->read(0, dst, 512); dst += 512; } } @@ -426,7 +475,7 @@ std::pair<err_t, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 } default: - data.first = ERR_UNSUPPORTED; + data.first = error::unsupported; data.second.clear(); return data; } @@ -435,13 +484,13 @@ std::pair<err_t, std::vector<u8>> prodos_impl::any_read(u8 type, u16 block, u32 return data; } -std::pair<err_t, std::vector<u8>> prodos_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> prodos_impl::file_read(const std::vector<std::string> &path) { auto [blk, off, dir] = path_find(path); if(!off || dir) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); - const u8 *entry = blk.rodata() + off; + const u8 *entry = blk->rodata() + off; u8 type = entry[0] >> 4; if(type >= 1 && type <= 3) @@ -449,25 +498,25 @@ std::pair<err_t, std::vector<u8>> prodos_impl::file_read(const std::vector<std:: else if(type == 5) { auto kblk = m_blockdev.get(get_u16le(entry+0x11)); - return any_read(kblk.r8(0x000), kblk.r16l(0x001), kblk.r24l(0x005)); + return any_read(kblk->r8(0x000), kblk->r16l(0x001), kblk->r24l(0x005)); } else - return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>()); + return std::make_pair(error::unsupported, std::vector<u8>()); } -std::pair<err_t, std::vector<u8>> prodos_impl::file_rsrc_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> prodos_impl::file_rsrc_read(const std::vector<std::string> &path) { auto [blk, off, dir] = path_find(path); if(!off || dir) - return std::make_pair(ERR_NOT_FOUND, std::vector<u8>()); + return std::make_pair(error::not_found, std::vector<u8>()); - const u8 *entry = blk.rodata() + off; + const u8 *entry = blk->rodata() + off; u8 type = entry[0] >> 4; if(type == 5) { auto kblk = m_blockdev.get(get_u16le(entry+0x11)); - return any_read(kblk.r8(0x100), kblk.r16l(0x101), kblk.r24l(0x105)); + return any_read(kblk->r8(0x100), kblk->r16l(0x101), kblk->r24l(0x105)); } else - return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>()); + return std::make_pair(error::unsupported, std::vector<u8>()); } diff --git a/src/lib/formats/fs_unformatted.cpp b/src/lib/formats/fs_unformatted.cpp index df618c6485d..995c2b76148 100644 --- a/src/lib/formats/fs_unformatted.cpp +++ b/src/lib/formats/fs_unformatted.cpp @@ -35,11 +35,15 @@ void unformatted_image::enumerate_f(floppy_enumerator &fe) const u32 best_525 = form_factor == floppy_image::FF_525 ? - has_variant(variants, floppy_image::DSHD) ? FSI_525_DSHD : - has_variant(variants, floppy_image::DSQD) ? FSI_525_DSQD : - has_variant(variants, floppy_image::DSDD) ? FSI_525_DSDD : - has_variant(variants, floppy_image::SSQD) ? FSI_525_SSQD : - has_variant(variants, floppy_image::SSDD) ? FSI_525_SSDD : FSI_525_SSSD + has_variant(variants, floppy_image::DSHD) ? FSI_525_DSHD : + has_variant(variants, floppy_image::DSQD16) ? FSI_525_DSQD16 : + has_variant(variants, floppy_image::DSQD) ? FSI_525_DSQD : + has_variant(variants, floppy_image::DSDD16) ? FSI_525_DSDD16 : + has_variant(variants, floppy_image::DSDD) ? FSI_525_DSDD : + has_variant(variants, floppy_image::SSQD16) ? FSI_525_SSQD16 : + has_variant(variants, floppy_image::SSQD) ? FSI_525_SSQD : + has_variant(variants, floppy_image::SSDD16) ? FSI_525_SSDD16 : + has_variant(variants, floppy_image::SSDD) ? FSI_525_SSDD : FSI_525_SSSD : FSI_NONE; u32 best_35 = @@ -61,14 +65,22 @@ void unformatted_image::enumerate_f(floppy_enumerator &fe) const if(all || best_525 == FSI_525_DSHD) fe.add_raw("u525dshd", FSI_525_DSHD, "Unformatted 5\"25 double-sided high-density"); + if(all || best_525 == FSI_525_DSQD16) + fe.add_raw("u525dsqd16", FSI_525_DSQD16, "Unformatted 5\"25 double-sided quad-density 16 hard sectors"); if(all || best_525 == FSI_525_DSQD) fe.add_raw("u525dsqd", FSI_525_DSQD, "Unformatted 5\"25 double-sided quad-density"); + if(all || best_525 == FSI_525_DSDD16) + fe.add_raw("u525dsdd16", FSI_525_DSDD16, "Unformatted 5\"25 double-sided double-density 16 hard sectors"); if(all || best_525 == FSI_525_DSDD) fe.add_raw("u525dsdd", FSI_525_DSDD, "Unformatted 5\"25 double-sided double-density"); if(all) fe.add_raw("u525dssd", FSI_525_DSSD, "Unformatted 5\"25 double-sided single-density"); + if(all || best_525 == FSI_525_SSQD16) + fe.add_raw("u525ssqd16", FSI_525_SSQD16, "Unformatted 5\"25 single-sided quad-density 16 hard sectors"); if(all || best_525 == FSI_525_SSQD) fe.add_raw("u525ssqd", FSI_525_SSQD, "Unformatted 5\"25 single-sided quad-density"); + if(all || best_525 == FSI_525_SSDD16) + fe.add_raw("u525ssdd16", FSI_525_SSDD16, "Unformatted 5\"25 single-sided double-density 16 hard sectors"); if(all || best_525 == FSI_525_SSDD) fe.add_raw("u525ssdd", FSI_525_SSDD, "Unformatted 5\"25 single-sided double-density"); if(all || best_525 == FSI_525_SSSD) @@ -96,13 +108,17 @@ void unformatted_image::format(u32 key, floppy_image *image) case FSI_8_DSSD: image->set_form_variant(floppy_image::FF_8, floppy_image::DSSD); break; case FSI_8_SSSD: image->set_form_variant(floppy_image::FF_8, floppy_image::SSSD); break; - case FSI_525_DSHD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSHD); break; - case FSI_525_DSQD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSQD); break; - case FSI_525_DSDD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSDD); break; - case FSI_525_DSSD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSSD); break; - case FSI_525_SSQD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSQD); break; - case FSI_525_SSDD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSDD); break; - case FSI_525_SSSD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); break; + case FSI_525_DSHD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSHD); break; + case FSI_525_DSQD16: image->set_form_variant(floppy_image::FF_525, floppy_image::DSQD16); break; + case FSI_525_DSQD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSQD); break; + case FSI_525_DSDD16: image->set_form_variant(floppy_image::FF_525, floppy_image::DSDD16); break; + case FSI_525_DSDD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSDD); break; + case FSI_525_DSSD: image->set_form_variant(floppy_image::FF_525, floppy_image::DSSD); break; + case FSI_525_SSQD16: image->set_form_variant(floppy_image::FF_525, floppy_image::SSQD16); break; + case FSI_525_SSQD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSQD); break; + case FSI_525_SSDD16: image->set_form_variant(floppy_image::FF_525, floppy_image::SSDD16); break; + case FSI_525_SSDD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSDD); break; + case FSI_525_SSSD: image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); break; case FSI_35_DSED: image->set_form_variant(floppy_image::FF_35, floppy_image::DSED); break; case FSI_35_DSHD: image->set_form_variant(floppy_image::FF_35, floppy_image::DSHD); break; diff --git a/src/lib/formats/fs_unformatted.h b/src/lib/formats/fs_unformatted.h index 949bb6aae08..fa51049f384 100644 --- a/src/lib/formats/fs_unformatted.h +++ b/src/lib/formats/fs_unformatted.h @@ -25,10 +25,14 @@ public: FSI_525_SSSD, FSI_525_SSDD, + FSI_525_SSDD16, FSI_525_SSQD, + FSI_525_SSQD16, FSI_525_DSSD, FSI_525_DSDD, + FSI_525_DSDD16, FSI_525_DSQD, + FSI_525_DSQD16, FSI_525_DSHD, FSI_35_SSDD, diff --git a/src/lib/formats/fs_vtech.cpp b/src/lib/formats/fs_vtech.cpp index 27e7f93a056..163b2ae6d53 100644 --- a/src/lib/formats/fs_vtech.cpp +++ b/src/lib/formats/fs_vtech.cpp @@ -19,7 +19,7 @@ namespace fs { const vtech_image VTECH; } // Filesystem has no subdirectories. // // Track 0 sectors 0-14 have the file names. 16 bytes/entry -// offset 0 : File type 'T' (basic) or 'B' (binary) +// offset 0 : File type 'T' (basic), 'B' (binary), or some other letter (application-specific) // offset 1 : 0x3a // offset 2-9: File name // offset a : Track number of first file sector @@ -38,24 +38,24 @@ public: virtual ~vtech_impl() = default; virtual meta_data volume_metadata() override; - virtual err_t volume_metadata_change(const meta_data &info) override; - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path) override; - virtual err_t metadata_change(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition volume_metadata_change(const meta_data &info) override; + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path) override; + virtual std::error_condition metadata_change(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; - virtual err_t rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) override; - virtual err_t remove(const std::vector<std::string> &path) override; + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path) override; + virtual std::error_condition rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) override; + virtual std::error_condition remove(const std::vector<std::string> &path) override; - virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta) override; + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta) override; - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path) override; - virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path) override; + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data) override; - virtual err_t format(const meta_data &meta) override; + virtual std::error_condition format(const meta_data &meta) override; private: meta_data file_metadata(const u8 *entry); - std::tuple<fsblk_t::block_t, u32> file_find(std::string_view name); + std::tuple<fsblk_t::block_t::ptr, u32> file_find(std::string_view name); std::vector<std::pair<u8, u8>> allocate_blocks(u32 count); void free_blocks(const std::vector<std::pair<u8, u8>> &blocks); u32 free_block_count(); @@ -114,7 +114,9 @@ std::vector<meta_description> vtech_image::file_meta_description() const res.emplace_back(meta_description(meta_name::name, "", false, [](const meta_value &m) { return m.as_string().size() <= 8; }, "File name, 8 chars")); res.emplace_back(meta_description(meta_name::loading_address, 0x7ae9, false, [](const meta_value &m) { return m.as_number() < 0x10000; }, "Loading address of the file")); res.emplace_back(meta_description(meta_name::length, 0, true, nullptr, "Size of the file in bytes")); - res.emplace_back(meta_description(meta_name::basic, true, true, nullptr, "Basic file")); + res.emplace_back(meta_description(meta_name::file_type, "T", true, + [](const meta_value &m) { return m.as_string().size() == 1 && m.as_string()[0] >= 'A' && m.as_string()[0] <= 'Z'; }, + "File type (e.g. T = text, B = binary)")); return res; } @@ -122,10 +124,10 @@ vtech_impl::vtech_impl(fsblk_t &blockdev) : filesystem_t(blockdev, 128) { } -err_t vtech_impl::format(const meta_data &meta) +std::error_condition vtech_impl::format(const meta_data &meta) { - m_blockdev.fill(0); - return ERR_OK; + m_blockdev.fill_all(0); + return std::error_condition(); } meta_data vtech_impl::volume_metadata() @@ -133,9 +135,9 @@ meta_data vtech_impl::volume_metadata() return meta_data(); } -err_t vtech_impl::volume_metadata_change(const meta_data &meta) +std::error_condition vtech_impl::volume_metadata_change(const meta_data &meta) { - return ERR_OK; + return std::error_condition(); } meta_data vtech_impl::file_metadata(const u8 *entry) @@ -143,56 +145,56 @@ meta_data vtech_impl::file_metadata(const u8 *entry) meta_data res; res.set(meta_name::name, trim_end_spaces(rstr(entry+2, 8))); - res.set(meta_name::basic, entry[0] == 'T'); + res.set(meta_name::file_type, std::string{ char(entry[0]) }); res.set(meta_name::loading_address, get_u16le(entry + 0xc)); - res.set(meta_name::length, ((get_u16le(entry + 0xe) - get_u16le(entry + 0xc) + 1) & 0xffff)); + res.set(meta_name::length, (get_u16le(entry + 0xe) - get_u16le(entry + 0xc)) & 0xffff); return res; } -std::tuple<fsblk_t::block_t, u32> vtech_impl::file_find(std::string_view name) +std::tuple<fsblk_t::block_t::ptr, u32> vtech_impl::file_find(std::string_view name) { for(int sect = 0; sect != 14; sect++) { auto bdir = m_blockdev.get(sect); for(u32 i = 0; i != 8; i ++) { u32 off = i*16; - u8 type = bdir.r8(off); - if(type != 'T' && type != 'B') + u8 type = bdir->r8(off); + if(type < 'A' || type > 'Z') continue; - if(bdir.r8(off+1) != ':') + if(bdir->r8(off+1) != ':') continue; - if(trim_end_spaces(bdir.rstr(off+2, 8)) == name) { - return std::make_tuple(bdir, i); + if(trim_end_spaces(bdir->rstr(off+2, 8)) == name) { + return std::make_tuple(bdir, off); } } } - return std::make_tuple(fsblk_t::block_t(), 0xffffffff); + return std::make_tuple(fsblk_t::block_t::ptr(), 0xffffffff); } -std::pair<err_t, meta_data> vtech_impl::metadata(const std::vector<std::string> &path) +std::pair<std::error_condition, meta_data> vtech_impl::metadata(const std::vector<std::string> &path) { if(path.size() != 1) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); auto [bdir, off] = file_find(path[0]); if(off == 0xffffffff) - return std::make_pair(ERR_NOT_FOUND, meta_data()); + return std::make_pair(error::not_found, meta_data()); - return std::make_pair(ERR_OK, file_metadata(bdir.rodata() + off)); + return std::make_pair(std::error_condition(), file_metadata(bdir->rodata() + off)); } -err_t vtech_impl::metadata_change(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition vtech_impl::metadata_change(const std::vector<std::string> &path, const meta_data &meta) { if(path.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off] = file_find(path[0]); - if(!off) - return ERR_NOT_FOUND; + if(off == 0xffffffff) + return error::not_found; - u8 *entry = bdir.data() + off; - if(meta.has(meta_name::basic)) - entry[0x0] = meta.get_flag(meta_name::basic) ? 'T' : 'B'; + u8 *entry = bdir->data() + off; + if(meta.has(meta_name::file_type)) + entry[0x0] = meta.get_string(meta_name::file_type)[0]; if(meta.has(meta_name::name)) { std::string name = meta.get_string(meta_name::name); name.resize(8, ' '); @@ -205,103 +207,103 @@ err_t vtech_impl::metadata_change(const std::vector<std::string> &path, const me put_u16le(entry + 0xe, new_end); } - return ERR_OK; + return std::error_condition(); } -std::pair<err_t, std::vector<dir_entry>> vtech_impl::directory_contents(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<dir_entry>> vtech_impl::directory_contents(const std::vector<std::string> &path) { - std::pair<err_t, std::vector<dir_entry>> res; + std::pair<std::error_condition, std::vector<dir_entry>> res; if(path.size() != 0) { - res.first = ERR_NOT_FOUND; + res.first = error::not_found; return res; } - res.first = ERR_OK; + res.first = std::error_condition(); for(int sect = 0; sect != 14; sect++) { auto bdir = m_blockdev.get(sect); for(u32 i = 0; i != 8; i ++) { u32 off = i*16; - u8 type = bdir.r8(off); - if(type != 'T' && type != 'B') + u8 type = bdir->r8(off); + if(type < 'A' || type > 'Z') continue; - if(bdir.r8(off+1) != ':') + if(bdir->r8(off+1) != ':') continue; - meta_data meta = file_metadata(bdir.rodata()+off); + meta_data meta = file_metadata(bdir->rodata()+off); res.second.emplace_back(dir_entry(dir_entry_type::file, meta)); } } return res; } -err_t vtech_impl::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) +std::error_condition vtech_impl::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) { if(opath.size() != 1 || npath.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off] = file_find(opath[0]); - if(!off) - return ERR_NOT_FOUND; + if(off == 0xffffffff) + return error::not_found; std::string name = npath[0]; name.resize(8, ' '); - wstr(bdir.data() + off + 2, name); + wstr(bdir->data() + off + 2, name); - return ERR_OK; + return std::error_condition(); } -err_t vtech_impl::remove(const std::vector<std::string> &path) +std::error_condition vtech_impl::remove(const std::vector<std::string> &path) { - return ERR_NOT_FOUND; + return error::unsupported; } -err_t vtech_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition vtech_impl::file_create(const std::vector<std::string> &path, const meta_data &meta) { if(path.size() != 0) - return ERR_NOT_FOUND; + return error::not_found; // Find the key for the next unused entry for(int sect = 0; sect != 14; sect++) { auto bdir = m_blockdev.get(sect); for(u32 i = 0; i != 16; i ++) { u32 off = i*16; - u8 type = bdir.r8(off); + u8 type = bdir->r8(off); if(type != 'T' && type != 'B') { std::string fname = meta.get_string(meta_name::name, ""); fname.resize(8, ' '); - bdir.w8 (off+0x0, meta.get_flag(meta_name::basic, true) ? 'T' : 'B'); - bdir.w8 (off+0x1, ':'); - bdir.wstr(off+0x2, fname); - bdir.w8 (off+0xa, 0x00); - bdir.w8 (off+0xb, 0x00); - bdir.w16l(off+0xc, meta.get_number(meta_name::loading_address, 0x7ae9)); - bdir.w16l(off+0xe, bdir.r16l(off+0xc) - 1); // Size 0 initially - return ERR_OK; + bdir->w8 (off+0x0, meta.get_string(meta_name::file_type, "T")[0]); + bdir->w8 (off+0x1, ':'); + bdir->wstr(off+0x2, fname); + bdir->w8 (off+0xa, 0x00); + bdir->w8 (off+0xb, 0x00); + bdir->w16l(off+0xc, meta.get_number(meta_name::loading_address, 0x7ae9)); + bdir->w16l(off+0xe, bdir->r16l(off+0xc)); // Size 0 initially + return std::error_condition(); } } } - return ERR_NO_SPACE; + return error::no_space; } -std::pair<err_t, std::vector<u8>> vtech_impl::file_read(const std::vector<std::string> &path) +std::pair<std::error_condition, std::vector<u8>> vtech_impl::file_read(const std::vector<std::string> &path) { std::vector<u8> data; if(path.size() != 1) - return std::make_pair(ERR_NOT_FOUND, data); + return std::make_pair(error::not_found, data); auto [bdir, off] = file_find(path[0]); if(off == 0xffffffff) - return std::make_pair(ERR_NOT_FOUND, data); + return std::make_pair(error::not_found, data); - const u8 *entry = bdir.rodata() + off; + const u8 *entry = bdir->rodata() + off; u8 track = entry[0xa]; u8 sector = entry[0xb]; - int len = ((get_u16le(entry + 0xe) - get_u16le(entry + 0xc)) & 0xffff) + 1; + int len = (get_u16le(entry + 0xe) - get_u16le(entry + 0xc)) & 0xffff; data.resize(len, 0); int pos = 0; @@ -312,26 +314,26 @@ std::pair<err_t, std::vector<u8>> vtech_impl::file_read(const std::vector<std::s int size = len - pos; if(size > 126) size = 126; - memcpy(data.data() + pos, dblk.data(), size); + dblk->read(0, data.data() + pos, size); pos += size; - track = dblk.r8(126); - sector = dblk.r8(127); + track = dblk->r8(126); + sector = dblk->r8(127); } - return std::make_pair(ERR_OK, data); + return std::make_pair(std::error_condition(), data); } -err_t vtech_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::error_condition vtech_impl::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) { if(path.size() != 1) - return ERR_NOT_FOUND; + return error::not_found; auto [bdir, off] = file_find(path[0]); if(off == 0xffffffff) - return ERR_NOT_FOUND; + return error::not_found; - u8 *entry = bdir.data() + off; + u8 *entry = bdir->data() + off; - u32 cur_len = ((get_u16le(entry + 0xe) - get_u16le(entry + 0xc) + 1) & 0xffff); + u32 cur_len = (get_u16le(entry + 0xe) - get_u16le(entry + 0xc)) & 0xffff; u32 new_len = data.size(); if(new_len > 65535) new_len = 65535; @@ -340,7 +342,7 @@ err_t vtech_impl::file_write(const std::vector<std::string> &path, const std::ve // Enough space? if(cur_ns < need_ns && free_block_count() < need_ns - cur_ns) - return ERR_NO_SPACE; + return error::no_space; u8 track = entry[0xa]; u8 sector = entry[0xb]; @@ -348,8 +350,8 @@ err_t vtech_impl::file_write(const std::vector<std::string> &path, const std::ve for(u32 i = 0; i != cur_ns; i++) { tofree.emplace_back(std::make_pair(track, sector)); auto dblk = m_blockdev.get(track*16 + sector); - track = dblk.r8(126); - sector = dblk.r8(127); + track = dblk->r8(126); + sector = dblk->r8(127); } free_blocks(tofree); @@ -361,16 +363,16 @@ err_t vtech_impl::file_write(const std::vector<std::string> &path, const std::ve if(len > 126) len = 126; else if(len < 126) - dblk.fill(0x00); - memcpy(dblk.data(), data.data() + 126*i, len); + dblk->fill(0x00); + dblk->write(0, data.data() + 126*i, len); if(i < need_ns) { - dblk.w8(126, blocks[i+1].first); - dblk.w8(127, blocks[i+1].second); + dblk->w8(126, blocks[i+1].first); + dblk->w8(127, blocks[i+1].second); } else - dblk.w16l(126, 0); + dblk->w16l(126, 0); } - u16 end_address = (get_u16le(entry + 0xc) + data.size() - 1) & 0xffff; + u16 end_address = (get_u16le(entry + 0xc) + data.size()) & 0xffff; put_u16le(entry + 0xe, end_address); if(need_ns) { entry[0xa] = blocks[0].first; @@ -378,7 +380,7 @@ err_t vtech_impl::file_write(const std::vector<std::string> &path, const std::ve } else put_u16le(entry + 0xa, 0); - return ERR_OK; + return std::error_condition(); } std::vector<std::pair<u8, u8>> vtech_impl::allocate_blocks(u32 count) @@ -392,8 +394,8 @@ std::vector<std::pair<u8, u8>> vtech_impl::allocate_blocks(u32 count) for(u8 sector = 0; sector != 16; sector++) { u32 off = (track-1)*2 + (sector / 8); u32 bit = 1 << (sector & 7); - if(!(fmap.r8(off) & bit)) { - fmap.w8(off, fmap.r8(off) | bit); + if(!(fmap->r8(off) & bit)) { + fmap->w8(off, fmap->r8(off) | bit); blocks.emplace_back(std::make_pair(track, sector)); if(blocks.size() == count) return blocks; @@ -410,7 +412,7 @@ void vtech_impl::free_blocks(const std::vector<std::pair<u8, u8>> &blocks) u8 sector = ref.second; u32 off = (track-1)*2 + (sector / 8); u32 bit = 1 << (sector & 7); - fmap.w8(off, fmap.r8(off) & ~bit); + fmap->w8(off, fmap->r8(off) & ~bit); } } @@ -419,7 +421,7 @@ u32 vtech_impl::free_block_count() auto fmap = m_blockdev.get(15); u32 nf = 0; for(u32 off = 0; off != (40-1)*2; off++) { - u8 m = fmap.r8(off); + u8 m = fmap->r8(off); // Count 1 bits; m = ((m & 0xaa) >> 1) | (m & 0x55); m = ((m & 0xcc) >> 2) | (m & 0x33); diff --git a/src/lib/formats/fsblk.cpp b/src/lib/formats/fsblk.cpp index d766e389bee..5e8198d0ce8 100644 --- a/src/lib/formats/fsblk.cpp +++ b/src/lib/formats/fsblk.cpp @@ -13,154 +13,124 @@ namespace fs { -void refcounted_inner::ref() -{ - m_ref ++; -} - -void refcounted_inner::ref_weak() -{ - m_weak_ref ++; -} - -bool refcounted_inner::unref() -{ - m_ref --; - if(m_ref == 0) { - if(m_weak_ref) - drop_weak_references(); - else - delete this; - return true; - } - return false; -} - -bool refcounted_inner::unref_weak() -{ - m_weak_ref --; - if(m_weak_ref == 0 && m_ref == 0) { - delete this; - return true; - } - return false; -} - - - void fsblk_t::set_block_size(u32 block_size) { m_block_size = block_size; } -u8 *fsblk_t::iblock_t::offset(const char *function, u32 off, u32 size) +const u8 *fsblk_t::block_t::roffs(const char *function, u32 off, u32 size) const { if(off + size > m_size) - throw std::out_of_range(util::string_format("block_t::%s out-of-block access, offset=%d, size=%d, block size=%d", function, off, size, m_size)); - return data() + off; + throw std::out_of_range(util::string_format("block_t::%s out-of-block read access, offset=%d, size=%d, block size=%d", function, off, size, m_size)); + return rodata() + off; } -const u8 *fsblk_t::iblock_t::rooffset(const char *function, u32 off, u32 size) +u8 *fsblk_t::block_t::woffs(const char *function, u32 off, u32 size) { if(off + size > m_size) - throw std::out_of_range(util::string_format("block_t::%s out-of-block read access, offset=%d, size=%d, block size=%d\n", function, off, size, m_size)); - return rodata() + off; + throw std::out_of_range(util::string_format("block_t::%s out-of-block access, offset=%d, size=%d, block size=%d", function, off, size, m_size)); + return data() + off; } -void fsblk_t::block_t::copy(u32 offset, const u8 *src, u32 size) +void fsblk_t::block_t::write(u32 offset, const u8 *src, u32 size) { - memcpy(m_object->offset("copy", offset, size), src, size); + memcpy(woffs("write", offset, size), src, size); } void fsblk_t::block_t::fill(u32 offset, u8 data, u32 size) { - memset(m_object->offset("fill", offset, size), data, size); + memset(woffs("fill", offset, size), data, size); } void fsblk_t::block_t::fill(u8 data) { - memset(m_object->data(), data, m_object->size()); + memset(this->data(), data, size()); } void fsblk_t::block_t::wstr(u32 offset, std::string_view str) { - memcpy(m_object->offset("wstr", offset, str.size()), str.data(), str.size()); + memcpy(woffs("wstr", offset, str.size()), str.data(), str.size()); } void fsblk_t::block_t::w8(u32 offset, u8 data) { - m_object->offset("w8", offset, 1)[0] = data; + woffs("w8", offset, 1)[0] = data; } void fsblk_t::block_t::w16b(u32 offset, u16 data) { - put_u16be(m_object->offset("w16b", offset, 2), data); + put_u16be(woffs("w16b", offset, 2), data); } void fsblk_t::block_t::w24b(u32 offset, u32 data) { - put_u24be(m_object->offset("w24b", offset, 3), data); + put_u24be(woffs("w24b", offset, 3), data); } void fsblk_t::block_t::w32b(u32 offset, u32 data) { - put_u32be(m_object->offset("w32b", offset, 4), data); + put_u32be(woffs("w32b", offset, 4), data); } void fsblk_t::block_t::w16l(u32 offset, u16 data) { - put_u16le(m_object->offset("w16l", offset, 2), data); + put_u16le(woffs("w16l", offset, 2), data); } void fsblk_t::block_t::w24l(u32 offset, u32 data) { - put_u24le(m_object->offset("w24l", offset, 3), data); + put_u24le(woffs("w24l", offset, 3), data); } void fsblk_t::block_t::w32l(u32 offset, u32 data) { - put_u32le(m_object->offset("w32l", offset, 4), data); + put_u32le(woffs("w32l", offset, 4), data); +} + +void fsblk_t::block_t::read(u32 offset, u8 *dst, u32 size) const +{ + memcpy(dst, roffs("read", offset, size), size); } std::string_view fsblk_t::block_t::rstr(u32 offset, u32 size) const { - const u8 *d = m_object->rooffset("rstr", offset, size); + const u8 *d = roffs("rstr", offset, size); return std::string_view(reinterpret_cast<const char *>(d), size); } u8 fsblk_t::block_t::r8(u32 offset) const { - return m_object->offset("r8", offset, 1)[0]; + return roffs("r8", offset, 1)[0]; } u16 fsblk_t::block_t::r16b(u32 offset) const { - return get_u16be(m_object->offset("r16b", offset, 2)); + return get_u16be(roffs("r16b", offset, 2)); } u32 fsblk_t::block_t::r24b(u32 offset) const { - return get_u24be(m_object->offset("r24b", offset, 3)); + return get_u24be(roffs("r24b", offset, 3)); } u32 fsblk_t::block_t::r32b(u32 offset) const { - return get_u32be(m_object->offset("r32b", offset, 4)); + return get_u32be(roffs("r32b", offset, 4)); } u16 fsblk_t::block_t::r16l(u32 offset) const { - return get_u16le(m_object->offset("r16l", offset, 2)); + return get_u16le(roffs("r16l", offset, 2)); } u32 fsblk_t::block_t::r24l(u32 offset) const { - return get_u24le(m_object->offset("r24l", offset, 3)); + return get_u24le(roffs("r24l", offset, 3)); } u32 fsblk_t::block_t::r32l(u32 offset) const { - return get_u32le(m_object->offset("r32l", offset, 4)); + return get_u32le(roffs("r32l", offset, 4)); } @@ -186,69 +156,99 @@ meta_data filesystem_t::volume_metadata() return meta_data(); } -err_t filesystem_t::volume_metadata_change(const meta_data &meta) +std::error_condition filesystem_t::volume_metadata_change(const meta_data &meta) +{ + return error::unsupported; +} + +std::pair<std::error_condition, meta_data> filesystem_t::metadata(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return std::make_pair(error::unsupported, meta_data()); } -std::pair<err_t, meta_data> filesystem_t::metadata(const std::vector<std::string> &path) +std::error_condition filesystem_t::metadata_change(const std::vector<std::string> &path, const meta_data &meta) { - return std::make_pair(ERR_UNSUPPORTED, meta_data()); + return error::unsupported; } -err_t filesystem_t::metadata_change(const std::vector<std::string> &path, const meta_data &meta) +std::pair<std::error_condition, std::vector<dir_entry>> filesystem_t::directory_contents(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return std::make_pair(error::unsupported, std::vector<dir_entry>()); } -std::pair<err_t, std::vector<dir_entry>> filesystem_t::directory_contents(const std::vector<std::string> &path) +std::error_condition filesystem_t::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) { - return std::make_pair(ERR_UNSUPPORTED, std::vector<dir_entry>()); + return error::unsupported; } -err_t filesystem_t::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath) +std::error_condition filesystem_t::remove(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return error::unsupported; } -err_t filesystem_t::remove(const std::vector<std::string> &path) +std::error_condition filesystem_t::dir_create(const std::vector<std::string> &path, const meta_data &meta) { - return ERR_UNSUPPORTED; + return error::unsupported; } -err_t filesystem_t::dir_create(const std::vector<std::string> &path, const meta_data &meta) +std::error_condition filesystem_t::file_create(const std::vector<std::string> &path, const meta_data &meta) { - return ERR_UNSUPPORTED; + return error::unsupported; } -err_t filesystem_t::file_create(const std::vector<std::string> &path, const meta_data &meta) +std::pair<std::error_condition, std::vector<u8>> filesystem_t::file_read(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return std::make_pair(error::unsupported, std::vector<u8>()); } -std::pair<err_t, std::vector<u8>> filesystem_t::file_read(const std::vector<std::string> &path) +std::error_condition filesystem_t::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) { - return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>()); + return error::unsupported; } -err_t filesystem_t::file_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::pair<std::error_condition, std::vector<u8>> filesystem_t::file_rsrc_read(const std::vector<std::string> &path) { - return ERR_UNSUPPORTED; + return std::make_pair(error::unsupported, std::vector<u8>()); } -std::pair<err_t, std::vector<u8>> filesystem_t::file_rsrc_read(const std::vector<std::string> &path) +std::error_condition filesystem_t::file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data) { - return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>()); + return error::unsupported; } -err_t filesystem_t::file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data) +std::error_condition filesystem_t::format(const meta_data &meta) { - return ERR_UNSUPPORTED; + return error::unsupported; } -err_t filesystem_t::format(const meta_data &meta) +std::error_category const &fs_category() noexcept { - return ERR_UNSUPPORTED; + class fs_category_impl : public std::error_category + { + public: + virtual char const *name() const noexcept override { return "fs"; } + + virtual std::string message(int condition) const override + { + using namespace std::literals; + static std::string_view const s_messages[] = { + "No error"sv, + "Unsupported operation"sv, + "File or directory not found"sv, + "No space on volume"sv, + "Invalid block number"sv, + "Invalid filename or path"sv, + "Incorrect file size"sv, + "File already exists"sv, + }; + if ((0 <= condition) && (std::size(s_messages) > condition)) + return std::string(s_messages[condition]); + else + return "Unknown error"s; + } + }; + static fs_category_impl const s_fs_category_instance; + return s_fs_category_instance; } } // namespace fs diff --git a/src/lib/formats/fsblk.h b/src/lib/formats/fsblk.h index 63ed910a507..7f368a7307c 100644 --- a/src/lib/formats/fsblk.h +++ b/src/lib/formats/fsblk.h @@ -10,8 +10,10 @@ #include "fsmeta.h" +#include <memory> #include <string> #include <string_view> +#include <system_error> #include <utility> #include <vector> @@ -22,110 +24,14 @@ using u16 = uint16_t; using u32 = uint32_t; using u64 = uint64_t; -enum err_t { - ERR_OK = 0, - ERR_UNSUPPORTED, - ERR_INVALID, - ERR_NOT_FOUND, - ERR_NOT_EMPTY, - ERR_NO_SPACE, -}; - -template<typename T> class refcounted_outer { -public: - refcounted_outer(bool weak) : m_object(nullptr), m_is_weak_ref(weak) {} - refcounted_outer(T *object, bool weak) : m_object(object), m_is_weak_ref(weak) { - ref(); - } - - refcounted_outer(const refcounted_outer &cref) { - m_object = cref.m_object; - m_is_weak_ref = cref.m_is_weak_ref; - ref(); - } - - refcounted_outer(refcounted_outer &&cref) { - m_object = cref.m_object; - m_is_weak_ref = cref.m_is_weak_ref; - cref.m_object = nullptr; - } - - ~refcounted_outer() { - unref(); - } - - refcounted_outer<T> &operator =(T *dir) { - if(m_object != dir) { - unref(); - m_object = dir; - ref(); - } - return *this; - } - - refcounted_outer<T> &operator =(const refcounted_outer<T> &cref) { - if(m_object != cref.m_object) { - unref(); - m_object = cref.m_object; - ref(); - } - return *this; - } - - refcounted_outer<T> &operator =(refcounted_outer<T> &&cref) { - if(m_object != cref.m_object) { - unref(); - m_object = cref.m_object; - ref(); - } else if(m_is_weak_ref != cref.m_is_weak_ref) { - ref(); - cref.unref(); - m_object = cref.m_object; // In case the object got deleted (when going from strong ref to weak on the last strong) - } - cref.m_object = nullptr; - return *this; - } - - operator bool() const { return m_object != nullptr; } - -protected: - T *m_object; - bool m_is_weak_ref; - -private: - void ref() { - if(m_object) { - if(m_is_weak_ref) - m_object->ref_weak(); - else - m_object->ref(); - } - } - - void unref() { - if(m_object) { - bool del = m_is_weak_ref ? m_object->unref_weak() : m_object->unref(); - if(del) - m_object = nullptr; - } - } -}; - - -class refcounted_inner { -public: - refcounted_inner() : m_ref(0), m_weak_ref(0) {} - virtual ~refcounted_inner() = default; - - void ref(); - void ref_weak(); - bool unref(); - bool unref_weak(); - - virtual void drop_weak_references() = 0; - -public: - u32 m_ref, m_weak_ref; +enum class error : int { + unsupported = 1, + not_found, + no_space, + invalid_block, + invalid_name, + incorrect_size, + already_exists, }; enum class dir_entry_type { @@ -142,51 +48,32 @@ struct dir_entry { }; class fsblk_t { -protected: - class iblock_t : public refcounted_inner { - public: - iblock_t(u32 size) : refcounted_inner(), m_size(size) {} - virtual ~iblock_t() = default; - - u32 size() const { return m_size; } - - virtual const u8 *rodata() = 0; - virtual u8 *data() = 0; - u8 *offset(const char *function, u32 off, u32 size); - const u8 *rooffset(const char *function, u32 off, u32 size); - - protected: - u32 m_size; - }; - - public: - class block_t : public refcounted_outer<iblock_t> { + class block_t { public: - block_t(bool weak = false) : refcounted_outer<iblock_t>(weak) {} - block_t(iblock_t *block, bool weak = true) : refcounted_outer(block, weak) {} - virtual ~block_t() = default; - - block_t strong() { return block_t(m_object, false); } - block_t weak() { return block_t(m_object, true); } + using ptr = std::shared_ptr<block_t>; - u32 size() const { return m_object->size(); } + block_t(u32 size) : m_size(size) {} + virtual ~block_t() = default; - const u8 *rodata() const { return m_object->rodata(); } - u8 *data() { return m_object->data(); } + u32 size() const { return m_size; } - void copy(u32 offset, const u8 *src, u32 size); - void fill( u8 data); - void fill(u32 offset, u8 data, u32 size); - void wstr(u32 offset, std::string_view str); - void w8( u32 offset, u8 data); - void w16b(u32 offset, u16 data); - void w24b(u32 offset, u32 data); - void w32b(u32 offset, u32 data); - void w16l(u32 offset, u16 data); - void w24l(u32 offset, u32 data); - void w32l(u32 offset, u32 data); + virtual const u8 *rodata() const = 0; + virtual u8 *data() = 0; + void write(u32 offset, const u8 *src, u32 size); + void fill( u8 data); + void fill( u32 offset, u8 data, u32 size); + void wstr( u32 offset, std::string_view str); + void w8( u32 offset, u8 data); + void w16b( u32 offset, u16 data); + void w24b( u32 offset, u32 data); + void w32b( u32 offset, u32 data); + void w16l( u32 offset, u16 data); + void w24l( u32 offset, u32 data); + void w32l( u32 offset, u32 data); + + void read(u32 offset, u8 *dst, u32 size) const; std::string_view rstr(u32 offset, u32 size) const; u8 r8( u32 offset) const; u16 r16b(u32 offset) const; @@ -195,6 +82,13 @@ public: u16 r16l(u32 offset) const; u32 r24l(u32 offset) const; u32 r32l(u32 offset) const; + + protected: + u32 m_size; + + private: + const u8 *roffs(const char *function, u32 off, u32 size) const; + u8 *woffs(const char *function, u32 off, u32 size); }; fsblk_t() : m_block_size(0) {} @@ -202,8 +96,8 @@ public: virtual void set_block_size(u32 block_size); virtual u32 block_count() const = 0; - virtual block_t get(u32 id) = 0; - virtual void fill(u8 data) = 0; + virtual block_t::ptr get(u32 id) = 0; + virtual void fill_all(u8 data) = 0; protected: u32 m_block_size; @@ -218,44 +112,44 @@ public: virtual meta_data volume_metadata(); // Change the metadata for the volume - virtual err_t volume_metadata_change(const meta_data &meta); + virtual std::error_condition volume_metadata_change(const meta_data &meta); // Get the metadata for a file or a directory. Empty path targets the root directory - virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path); + virtual std::pair<std::error_condition, meta_data> metadata(const std::vector<std::string> &path); // Change the metadata for a file or a directory. Empty path targets the root directory - virtual err_t metadata_change(const std::vector<std::string> &path, const meta_data &meta); + virtual std::error_condition metadata_change(const std::vector<std::string> &path, const meta_data &meta); // Get the contents of a directory, empty path targets the root directory - virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path); + virtual std::pair<std::error_condition, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path); // Rename a file or a directory. In contrast to metadata_change, this can move the object // between directories - virtual err_t rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath); + virtual std::error_condition rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath); // Remove a file or a directory. Directories must be empty (e.g. it's not recursive) - virtual err_t remove(const std::vector<std::string> &path); + virtual std::error_condition remove(const std::vector<std::string> &path); // Create a directory, path designates where the directory must be, directory name is in meta - virtual err_t dir_create(const std::vector<std::string> &path, const meta_data &meta); + virtual std::error_condition dir_create(const std::vector<std::string> &path, const meta_data &meta); // Create an empty file, path designates where the file must be, file name is in meta - virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta); + virtual std::error_condition file_create(const std::vector<std::string> &path, const meta_data &meta); // Read the contents of a file - virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path); + virtual std::pair<std::error_condition, std::vector<u8>> file_read(const std::vector<std::string> &path); // Replace the contents of a file, the file must already exist - virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data); + virtual std::error_condition file_write(const std::vector<std::string> &path, const std::vector<u8> &data); // Read the resource fork of a file on systems that handle those - virtual std::pair<err_t, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path); + virtual std::pair<std::error_condition, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path); // Replace the resource fork of a file, the file must already exist - virtual err_t file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data); + virtual std::error_condition file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data); // Format an image, provide the volume metadata - virtual err_t format(const meta_data &meta); + virtual std::error_condition format(const meta_data &meta); static void wstr(u8 *p, std::string_view str); @@ -271,6 +165,17 @@ protected: fsblk_t &m_blockdev; }; +// error category for filesystem errors +std::error_category const &fs_category() noexcept; +inline std::error_condition make_error_condition(error err) noexcept { return std::error_condition(int(err), fs_category()); } + } // namespace fs + +namespace std { + +template <> struct is_error_condition_enum<fs::error> : public std::true_type { }; + +} // namespace std + #endif diff --git a/src/lib/formats/fsblk_vec.cpp b/src/lib/formats/fsblk_vec.cpp index 36f11cc9d89..a04d60c263c 100644 --- a/src/lib/formats/fsblk_vec.cpp +++ b/src/lib/formats/fsblk_vec.cpp @@ -12,7 +12,7 @@ namespace fs { -const u8 *fsblk_vec_t::blk_t::rodata() +const u8 *fsblk_vec_t::blk_t::rodata() const { return m_data; } @@ -22,23 +22,19 @@ u8 *fsblk_vec_t::blk_t::data() return m_data; } -void fsblk_vec_t::blk_t::drop_weak_references() -{ -} - u32 fsblk_vec_t::block_count() const { return m_data.size() / m_block_size; } -fsblk_t::block_t fsblk_vec_t::get(u32 id) +fsblk_vec_t::block_t::ptr fsblk_vec_t::get(u32 id) { if(id >= block_count()) - throw std::out_of_range(util::string_format("Block number overflow: requiring block %d on device of size %d (%d bytes, block size %d)\n", id, block_count(), m_data.size(), m_block_size)); - return block_t(new blk_t(m_data.data() + m_block_size*id, m_block_size)); + throw std::out_of_range(util::string_format("Block number overflow: requiring block %d on device of size %d (%d bytes, block size %d)", id, block_count(), m_data.size(), m_block_size)); + return std::make_shared<blk_t>(m_data.data() + m_block_size*id, m_block_size); } -void fsblk_vec_t::fill(u8 data) +void fsblk_vec_t::fill_all(u8 data) { std::fill(m_data.begin(), m_data.end(), data); } diff --git a/src/lib/formats/fsblk_vec.h b/src/lib/formats/fsblk_vec.h index 49f7ed3013e..b029bc55c5e 100644 --- a/src/lib/formats/fsblk_vec.h +++ b/src/lib/formats/fsblk_vec.h @@ -9,14 +9,13 @@ namespace fs { class fsblk_vec_t : public fsblk_t { private: - class blk_t : public iblock_t { + class blk_t : public block_t { public: - blk_t(u8 *data, u32 size) : iblock_t(size), m_data(data) {} + blk_t(u8 *data, u32 size) : block_t(size), m_data(data) {} virtual ~blk_t() = default; - virtual const u8 *rodata() override; + virtual const u8 *rodata() const override; virtual u8 *data() override; - virtual void drop_weak_references() override; private: u8 *m_data; @@ -27,8 +26,8 @@ public: virtual ~fsblk_vec_t() = default; virtual u32 block_count() const override; - virtual block_t get(u32 id) override; - virtual void fill(u8 data) override; + virtual block_t::ptr get(u32 id) override; + virtual void fill_all(u8 data) override; private: std::vector<u8> &m_data; diff --git a/src/lib/formats/fsd_dsk.cpp b/src/lib/formats/fsd_dsk.cpp index e4909ba37f3..b386dc026c6 100644 --- a/src/lib/formats/fsd_dsk.cpp +++ b/src/lib/formats/fsd_dsk.cpp @@ -91,9 +91,11 @@ bool fsd_format::supports_save() const noexcept int fsd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[3]; - - size_t actual; - io.read_at(0, h, 3, actual); + auto const [err, actual] = read_at(io, 0, h, 3); + if (err || (3 != actual)) { + LOG_FORMATS("fsd: read error\n"); + return 0; + } if (memcmp(h, "FSD", 3) == 0) { return FIFID_SIGN; } @@ -111,9 +113,9 @@ bool fsd_format::load(util::random_read &io, uint32_t form_factor, const std::ve uint64_t size; if(io.length(size)) return false; - std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [err, img, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return false; uint64_t pos; std::string title; diff --git a/src/lib/formats/fsmeta.cpp b/src/lib/formats/fsmeta.cpp index f3e91e706a0..3c731f21939 100644 --- a/src/lib/formats/fsmeta.cpp +++ b/src/lib/formats/fsmeta.cpp @@ -14,7 +14,6 @@ namespace fs { const char *meta_data::entry_name(meta_name name) { switch(name) { - case meta_name::basic: return "basic"; case meta_name::creation_date: return "creation_date"; case meta_name::length: return "length"; case meta_name::loading_address: return "loading_address"; diff --git a/src/lib/formats/fsmeta.h b/src/lib/formats/fsmeta.h index 0f6baf20133..ff0b505ab8b 100644 --- a/src/lib/formats/fsmeta.h +++ b/src/lib/formats/fsmeta.h @@ -21,7 +21,6 @@ namespace fs { enum class meta_name { - basic, creation_date, length, loading_address, diff --git a/src/lib/formats/g64_dsk.cpp b/src/lib/formats/g64_dsk.cpp index 568cc8f5027..177438dc9a6 100644 --- a/src/lib/formats/g64_dsk.cpp +++ b/src/lib/formats/g64_dsk.cpp @@ -36,9 +36,10 @@ const uint32_t g64_format::c1541_cell_size[] = int g64_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { char h[8]; + auto const [err, actual] = read_at(io, 0, h, 8); + if (err || (8 != actual)) + return 0; - size_t actual; - io.read_at(0, h, 8, actual); if (!memcmp(h, G64_FORMAT_HEADER, 8)) return FIFID_SIGN; @@ -51,9 +52,9 @@ bool g64_format::load(util::random_read &io, uint32_t form_factor, const std::ve if (io.length(size)) return false; - std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [err, img, actual] = read_at(io, 0, size); + if (err || (actual != size)) + return false; if (img[POS_VERSION]) { @@ -124,7 +125,6 @@ bool g64_format::save(util::random_read_write &io, const std::vector<uint32_t> & { 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); @@ -132,7 +132,7 @@ bool g64_format::save(util::random_read_write &io, const std::vector<uint32_t> & // 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.write_at(POS_SIGNATURE, header, sizeof(header), actual); + write_at(io, POS_SIGNATURE, header, sizeof(header)); // FIXME: check for errors // write tracks for (int head = 0; head < heads; head++) { @@ -145,8 +145,8 @@ bool g64_format::save(util::random_read_write &io, const std::vector<uint32_t> & uint32_t const spos = tpos + (tracks * 4); uint32_t const dpos = POS_TRACK_OFFSET + (tracks * 4 * 2) + (tracks_written * TRACK_LENGTH); - io.write_at(tpos, zerofill, 4, actual); - io.write_at(spos, zerofill, 4, actual); + write_at(io, tpos, zerofill, 4); // FIXME: check for errors + write_at(io, spos, zerofill, 4); // FIXME: check for errors if (image.get_buffer(track, head).size() <= 1) continue; @@ -178,11 +178,11 @@ bool g64_format::save(util::random_read_write &io, const std::vector<uint32_t> & put_u32le(speed_offset, speed_zone); put_u16le(track_length, 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); + write_at(io, tpos, track_offset, 4); // FIXME: check for errors + write_at(io, spos, speed_offset, 4); // FIXME: check for errors + write_at(io, dpos, prefill.data(), TRACK_LENGTH); // FIXME: check for errors + write_at(io, dpos, track_length, 2); // FIXME: check for errors + write_at(io, dpos + 2, packed.data(), packed.size()); // FIXME: check for errors tracks_written++; } diff --git a/src/lib/formats/gtp_cas.cpp b/src/lib/formats/gtp_cas.cpp index 85caa73fd02..dc996aa89db 100644 --- a/src/lib/formats/gtp_cas.cpp +++ b/src/lib/formats/gtp_cas.cpp @@ -127,7 +127,7 @@ static int gtp_cas_to_wav_size( const uint8_t *casdata, int caslen ) { return size; } -static int gtp_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int gtp_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i,size,n; size = 0; n = 0; diff --git a/src/lib/formats/h17disk.cpp b/src/lib/formats/h17disk.cpp new file mode 100644 index 00000000000..9fb211ddb0d --- /dev/null +++ b/src/lib/formats/h17disk.cpp @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/********************************************************************* + +Heath H17D disk image format (version 2.0.0) + + Format for Heath hard-sectored 5.25" disk images. + + See https://heathkit.garlanger.com/diskformats/ for more information + + TODO - implement writing to H17D image + +*********************************************************************/ + +#include "h17disk.h" + +#include "imageutl.h" + +#include "ioprocs.h" + +#include <cstring> + + +namespace { + +constexpr int TRACK_SIZE = 50'000; +constexpr int BITCELL_SIZE = 4000; + +constexpr int SECTOR_METADATA_SIZE = 16; + +constexpr int SECTOR_DATA_SIZE = 256; +constexpr int SECTORS_PER_TRACK = 10; + +struct format { + int head_count; + int track_count; + uint32_t variant; +}; + +const format formats[] = { + { 1, 40, floppy_image::SSSD10 }, // H-17-1 + { 2, 40, floppy_image::DSSD10 }, + { 1, 80, floppy_image::SSQD10 }, + { 2, 80, floppy_image::DSQD10 }, // H-17-4 + {} +}; + +struct block_header { + uint32_t block_name; + uint32_t length; +}; + +enum { + DskF = 0x466b7344, //!< "DskF", Disk Format + Parm = 0x6b726150, //!< "Parm", Parameters + Date = 0x65746144, //!< "Date", Date + Imgr = 0x72676d49, //!< "Imgr", Imager + + Prog = 0x676f7250, //!< "Prog", Program (creation) + Padd = 0x64646150, //!< "Padd", Padding + H8DB = 0x42443848, //!< "H8DB", H8D data block + SecM = 0x4d636553, //!< "SecM", Sector Metadata + Labl = 0x6c62614c, //!< "Labl", Label + Comm = 0x6d6d6f43, //!< "Comm", Comment +}; + +std::pair<std::uint64_t, std::size_t> find_block(util::random_read &io, uint32_t block_id) +{ + LOG_FORMATS("find_block: 0x%x\n", block_id); + + // start of file + int pos = 0; + block_header header = { 0, 0 }; + + do + { + pos += header.length + 8; + auto const [err, actual] = read_at(io, pos, (void *) &header, 8); + if (err || actual !=8) + { + return std::make_pair(0, 0); + } + header.length = swapendian_int32(header.length); + } + while (header.block_name != block_id); + + // update position to point to data portion of the block + return std::make_pair(pos + 8, header.length); +} + +format find_format(util::random_read &io) +{ + auto const [pos, length] = find_block(io, DskF); + if ((pos == 0) || (length < 2) || (length > 3)) + { + LOG_FORMATS("Can't find valid DskF block %d/%d\n", pos, length); + + return {}; + } + + uint8_t buf[3]; + + auto const [err, actual] = read_at(io, pos, buf, length); + if (err || (actual != length)) + { + LOG_FORMATS("read error\n"); + + return {}; + } + + int head_count = buf[0]; + int track_count = buf[1]; + + for (int i = 0; formats[i].head_count; i++) + { + if ((formats[i].head_count == head_count) && (formats[i].track_count == track_count)) + { + LOG_FORMATS("find_format format found: %d - variant: 0x%x\n", i, formats[i].variant); + + return formats[i]; + } + } + + LOG_FORMATS("Invalid disk format - heads: %d, tracks: %d\n", head_count, track_count); + return {}; +} + +} // anonymous namespace + + +heath_h17d_format::heath_h17d_format() : floppy_image_format_t() +{ +} + +int heath_h17d_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint8_t h[4]; + auto const [err, actual] = read_at(io, 0, h, 4); + + if (err || (actual != 4)) + { + return 0; + } + + // Verify "H17D" Signature. + if ((h[0] == 0x48) && (h[1] == 0x31) && (h[2] == 0x37) && (h[3] == 0x44)) + { + return FIFID_SIGN; + } + + return 0; +} + +bool heath_h17d_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const +{ + const format fmt = find_format(io); + + if (!fmt.head_count) + { + LOG_FORMATS("invalid format\n"); + + return false; + } + + image.set_variant(fmt.variant); + + std::vector<uint32_t> buf; + + auto const [secm_pos, secm_length] = find_block(io, SecM); + + uint8_t sector_meta_data[SECTOR_METADATA_SIZE]; + uint8_t sector_data[SECTOR_DATA_SIZE]; + + for (int head = 0; head < fmt.head_count; head++) + { + for (int track = 0; track < fmt.track_count; track++) + { + for (int sector = 0; sector < SECTORS_PER_TRACK; sector++) + { + int sect_meta_pos = (sector + (track * fmt.head_count + head) * SECTORS_PER_TRACK) * SECTOR_METADATA_SIZE + secm_pos; + + auto const [err, actual] = read_at(io, sect_meta_pos, sector_meta_data, SECTOR_METADATA_SIZE); + + if (err || (actual != SECTOR_METADATA_SIZE)) + { + LOG_FORMATS("unable to read sect meta data %d/%d/%d\n", head, track, sector); + + return false; + } + int data_offset = sector_meta_data[0] << 24 | sector_meta_data[1] << 16 | sector_meta_data[2] << 8 | sector_meta_data[3]; + + auto const [err2, actual2] = read_at(io, data_offset, sector_data, SECTOR_DATA_SIZE); + + if (err2 || (actual2 != SECTOR_DATA_SIZE)) + { + LOG_FORMATS("unable to read sect data %d/%d/%d\n", head, track, sector); + + return false; + } + + // Inital 15 zero bytes + for (int i = 0; i < 15; i++) + { + fm_reverse_byte_w(buf, 0); + } + + // header (sync byte, volume, track, sector, checksum) + for (int i = 0; i < 5; i++) + { + fm_reverse_byte_w(buf, sector_meta_data[5 + i]); + } + + // 12 zero bytes + for (int i = 0; i < 12; i++) + { + fm_reverse_byte_w(buf, 0); + } + + // data sync byte + fm_reverse_byte_w(buf, sector_meta_data[10]); + + // sector data + for (int i = 0; i < 256; i++) + { + fm_reverse_byte_w(buf, sector_data[i]); + } + + // sector data checksum + fm_reverse_byte_w(buf, sector_meta_data[11]); + + // trailing zero's until the next sector hole usually ~ 30 characters. + while (buf.size() < TRACK_SIZE / SECTORS_PER_TRACK * (sector + 1)) + { + fm_reverse_byte_w(buf, 0); + } + } + + generate_track_from_levels(track, head, buf, 0, image); + buf.clear(); + } + } + + return true; +} + +void heath_h17d_format::fm_reverse_byte_w(std::vector<uint32_t> &buffer, uint8_t val) const +{ + constexpr unsigned char lookup[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; + + fm_w(buffer, 8, lookup[val & 0x0f] << 4 | lookup[val >> 4], BITCELL_SIZE); +} + +const heath_h17d_format FLOPPY_H17D_FORMAT; diff --git a/src/lib/formats/h17disk.h b/src/lib/formats/h17disk.h new file mode 100644 index 00000000000..19ac0bac052 --- /dev/null +++ b/src/lib/formats/h17disk.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/********************************************************************* + +Heath h17disk disk image format + +The Heath hard-sectored disk format for the H8 and H89 systems with the +H17 controller on the H8 and the H-88-1 controller on the H89. + +*********************************************************************/ +#ifndef MAME_FORMATS_H17DISK_H +#define MAME_FORMATS_H17DISK_H + +#pragma once + +#include "flopimg.h" + +class heath_h17d_format : public floppy_image_format_t +{ +public: + heath_h17d_format(); + + int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + + const char *name() const noexcept override { return "h17disk"; } + const char *description() const noexcept override { return "Heath H17D disk image"; } + const char *extensions() const noexcept override { return "h17,h17d,h17disk"; } + bool supports_save() const noexcept override { return false; } + +protected: + + void fm_reverse_byte_w(std::vector<uint32_t> &buffer, uint8_t val) const; +}; + +extern const heath_h17d_format FLOPPY_H17D_FORMAT; + +#endif // MAME_FORMATS_H17DISK_H diff --git a/src/lib/formats/h8_cas.cpp b/src/lib/formats/h8_cas.cpp index c0d5d6dd925..526e411d5ae 100644 --- a/src/lib/formats/h8_cas.cpp +++ b/src/lib/formats/h8_cas.cpp @@ -1,147 +1,96 @@ // license:BSD-3-Clause -// copyright-holders:Robbbert +// copyright-holders:Robbbert,Mark Garlanger /******************************************************************** -Support for Heathkit H8 H8T cassette images +Support for Heathkit H8/H88 H8T cassette images Standard Kansas City format (300 baud) +TODO - investigate 1200 buad support, H8 should support it, but H88 does not. + We output a leader, followed by the contents of the H8T file. ********************************************************************/ #include "h8_cas.h" -#define WAVEENTRY_LOW -32768 -#define WAVEENTRY_HIGH 32767 - -#define H8_WAV_FREQUENCY 9600 - -// image size -static int h8_image_size; // FIXME: global variable prevents multiple instances - -static int h8_put_samples(int16_t *buffer, int sample_pos, int count, int level) -{ - if (buffer) - { - for (int i=0; i<count; i++) - buffer[sample_pos + i] = level; - } - - return count; -} - -static int h8_output_bit(int16_t *buffer, int sample_pos, bool bit) -{ - int samples = 0; - - for (uint8_t i = 0; i < 4; i++) - { - if (bit) - { - samples += h8_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW); - samples += h8_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH); - samples += h8_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW); - samples += h8_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH); - } - else - { - samples += h8_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW); - samples += h8_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH); - } - } - - return samples; -} - -static int h8_output_byte(int16_t *buffer, int sample_pos, uint8_t byte) -{ - int samples = 0; - uint8_t i; +#include "coretmpl.h" // BIT - // start bit - samples += h8_output_bit (buffer, sample_pos + samples, 0); - // data bits - for (i = 0; i<8; i++) - samples += h8_output_bit (buffer, sample_pos + samples, (byte >> i) & 1); +namespace { - // stop bits - for (i = 0; i<2; i++) - samples += h8_output_bit (buffer, sample_pos + samples, 1); - - return samples; -} +constexpr double ONE_FREQ = 1200.0; +constexpr double ONE_FREQ_VARIANCE = 300.0; +constexpr double ZERO_FREQ = 2400.0; +constexpr double ZERO_FREQ_VARIANCE = 600.0; -static int h8_handle_cassette(int16_t *buffer, const uint8_t *bytes) +const cassette_image::Modulation heath_h8t_modulation = { - uint32_t sample_count = 0; - uint32_t byte_count = 0; - uint32_t i; - - - // leader - for (i=0; i<2000; i++) - sample_count += h8_output_bit(buffer, sample_count, 1); - - // data - for (i=byte_count; i<h8_image_size; i++) - sample_count += h8_output_byte(buffer, sample_count, bytes[i]); - - return sample_count; -} - - -/******************************************************************* - Generate samples for the tape image -********************************************************************/ + cassette_image::MODULATION_SINEWAVE, + ONE_FREQ - ONE_FREQ_VARIANCE, ONE_FREQ, ONE_FREQ + ONE_FREQ_VARIANCE, + ZERO_FREQ - ZERO_FREQ_VARIANCE, ZERO_FREQ, ZERO_FREQ + ZERO_FREQ_VARIANCE +}; -static int h8_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +cassette_image::error heath_h8t_identify(cassette_image *cassette, cassette_image::Options *opts) { - return h8_handle_cassette(buffer, bytes); + return cassette->modulation_identify(heath_h8t_modulation, opts); } -/******************************************************************* - Calculate the number of samples needed for this tape image -********************************************************************/ -static int h8_cassette_calculate_size_in_samples(const uint8_t *bytes, int length) +cassette_image::error heath_h8t_load(cassette_image *cassette) { - h8_image_size = length; + cassette_image::error err = cassette_image::error::SUCCESS; + uint64_t image_size = cassette->image_size(); + double time_index = 0.0; + double time_displacement; + + auto const MODULATE = + [&cassette, &err, &time_index, &time_displacement] (unsigned value) + { + for (int i = 0; (i < (value ? 8 : 4)); i++) + { + err = cassette->put_modulated_data_bit(0, time_index, value, heath_h8t_modulation, &time_displacement); + if (cassette_image::error::SUCCESS == err) + time_index += time_displacement; + else + return; + } + }; + + // leader - 1 second + while ((cassette_image::error::SUCCESS == err) && (time_index < 1.0)) + MODULATE(1); + + for (uint64_t image_pos = 0; (cassette_image::error::SUCCESS == err) && (image_pos < image_size); image_pos++) + { + uint8_t data = cassette->image_read_byte(image_pos); - return h8_handle_cassette(nullptr, bytes); -} + // start bit + MODULATE(0); -static const cassette_image::LegacyWaveFiller h8_legacy_fill_wave = -{ - h8_cassette_fill_wave, // fill_wave - -1, // chunk_size - 0, // chunk_samples - h8_cassette_calculate_size_in_samples, // chunk_sample_calc - H8_WAV_FREQUENCY, // sample_frequency - 0, // header_samples - 0 // trailer_samples -}; + // data bits + for (int bit = 0; (cassette_image::error::SUCCESS == err) && (bit < 8); bit++) + MODULATE(util::BIT(data, bit)); -static cassette_image::error h8_cassette_identify(cassette_image *cassette, cassette_image::Options *opts) -{ - return cassette->legacy_identify(opts, &h8_legacy_fill_wave); -} + // stop bit + if (cassette_image::error::SUCCESS == err) + MODULATE(1); + } -static cassette_image::error h8_cassette_load(cassette_image *cassette) -{ - return cassette->legacy_construct(&h8_legacy_fill_wave); + return err; } -static const cassette_image::Format h8_cassette_image_format = +const cassette_image::Format heath_h8t_format = { "h8t", - h8_cassette_identify, - h8_cassette_load, + heath_h8t_identify, + heath_h8t_load, nullptr }; -CASSETTE_FORMATLIST_START(h8_cassette_formats) - CASSETTE_FORMAT(h8_cassette_image_format) +} + +CASSETTE_FORMATLIST_START( h8_cassette_formats ) + CASSETTE_FORMAT( heath_h8t_format ) CASSETTE_FORMATLIST_END diff --git a/src/lib/formats/h8_cas.h b/src/lib/formats/h8_cas.h index 8ad9f82006a..9c7ea02104a 100644 --- a/src/lib/formats/h8_cas.h +++ b/src/lib/formats/h8_cas.h @@ -1,10 +1,10 @@ // license:BSD-3-Clause -// copyright-holders:Robbbert +// copyright-holders:Robbbert,Mark Garlanger /********************************************************************* h8_cas.h - Format code for Heathkit H8 H8T cassette images + Format code for Heathkit H8/H88 H8T cassette images *********************************************************************/ #ifndef MAME_FORMATS_H8_CAS_H diff --git a/src/lib/formats/hect_tap.cpp b/src/lib/formats/hect_tap.cpp index 867d95cf4b0..cef1a730875 100644 --- a/src/lib/formats/hect_tap.cpp +++ b/src/lib/formats/hect_tap.cpp @@ -121,7 +121,7 @@ static int hector_handle_tap(int16_t *buffer, const uint8_t *casdata) if (data_pos>1) previous_block = casdata[data_pos-1]; - /* Handle block lenght on tape data */ + /* Handle block length on tape data */ block_size = casdata[data_pos] ; if (block_size==0) block_size=256; @@ -173,8 +173,8 @@ static int hector_handle_forth_tap(int16_t *buffer, const uint8_t *casdata) /* Starting a block with 768 cycle of synchro*/ sample_count += hector_tap_synchro( buffer, sample_count, 768 ); - /* Handle block lenght on tape data */ - block_size = 822 ; /* Fixed size for the forth*/ + /* Handle block length on tape data */ + block_size = 822 ; /* Fixed size for the forth */ /*block_count=0;*/ @@ -203,7 +203,7 @@ static int hector_handle_forth_tap(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int hector_tap_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int hector_tap_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return hector_handle_tap( buffer, bytes ); } @@ -222,7 +222,7 @@ static int hector_tap_forth_to_wav_size(const uint8_t *casdata, int caslen) /******************************************************************* Generate samples for the tape image FORTH ********************************************************************/ -static int hector_tap_forth_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int hector_tap_forth_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return hector_handle_forth_tap( buffer, bytes ); //forth removed here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } diff --git a/src/lib/formats/hp300_dsk.cpp b/src/lib/formats/hp300_dsk.cpp index de33bf6d310..99c3c20f283 100644 --- a/src/lib/formats/hp300_dsk.cpp +++ b/src/lib/formats/hp300_dsk.cpp @@ -30,11 +30,11 @@ const char *hp300_format::extensions() const noexcept } const hp300_format::format hp300_format::formats[] = { + { floppy_image::FF_35, floppy_image::SSDD, floppy_image::MFM, 2000, 16, 66, 1, 256, {}, 0, {}, 32, 22, 46 }, // FORMAT 4 // HP 9121S, 9121D or 9133A { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 16, 77, 2, 256, {}, 1, {}, 50, 22, 54 }, // FORMAT 0,1 { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 9, 77, 2, 512, {}, 1, {}, 50, 22, 89 }, // FORMAT 2 { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 5, 77, 2, 1024, {}, 1, {}, 50, 22, 108 }, // FORMAT 3 - { floppy_image::FF_35, floppy_image::DSSD, floppy_image::MFM, 2000, 16, 70, 1, 256, {}, 1, {}, 32, 22, 46 }, // FORMAT 4 { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 9, 80, 2, 512, {}, 1, {}, 146, 22, 81 }, // FORMAT 16 // HP9122C/D, 9123D, 9133D/H/L or 9153A/B { floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, 2000, 32, 77, 2, 256, {}, 1, {}, 50, 22, 59 }, // FORMAT 0,1,4 diff --git a/src/lib/formats/hpi_dsk.cpp b/src/lib/formats/hpi_dsk.cpp index 84836207222..952ec0a2709 100644 --- a/src/lib/formats/hpi_dsk.cpp +++ b/src/lib/formats/hpi_dsk.cpp @@ -162,9 +162,10 @@ bool hpi_format::load(util::random_read &io, uint32_t form_factor, const std::ve image.set_variant(heads == 2 ? floppy_image::DSDD : floppy_image::SSDD); // Suck in the whole image - std::vector<uint8_t> image_data(size); - size_t actual; - io.read_at(0, image_data.data(), size, actual); + auto const [err, image_data, actual] = read_at(io, 0, size); + if (err || (actual != size)) { + return false; + } // Get interleave factor from image unsigned il = (unsigned)image_data[ IL_OFFSET ] * 256 + image_data[ IL_OFFSET + 1 ]; @@ -209,8 +210,7 @@ bool hpi_format::save(util::random_read_write &io, const std::vector<uint32_t> & 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; - size_t actual; - io.write_at(offset_in_image, sector_data, HPI_SECTOR_SIZE, actual); + /*auto const [err, actual] =*/ write_at(io, offset_in_image, sector_data, HPI_SECTOR_SIZE); // FIXME: check for errors } } } diff --git a/src/lib/formats/hti_tape.cpp b/src/lib/formats/hti_tape.cpp index f4a5727d591..7d6119860f1 100644 --- a/src/lib/formats/hti_tape.cpp +++ b/src/lib/formats/hti_tape.cpp @@ -11,6 +11,8 @@ #include "ioprocs.h" #include "multibyte.h" +#include <tuple> + 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" @@ -54,10 +56,12 @@ bool hti_format_t::load_tape(util::random_read &io) return false; } - size_t actual; - uint8_t tmp[ 4 ]; + uint8_t tmp[4]; + auto const [err, actual] = read(io, tmp, 4); + if (err || (4 != actual)) { + return false; + } - io.read(tmp, 4, actual); auto magic = get_u32be(tmp); 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)) { @@ -65,7 +69,7 @@ bool hti_format_t::load_tape(util::random_read &io) } for (unsigned i = 0; i < no_of_tracks(); i++) { - tape_track_t& track = m_tracks[ i ]; + tape_track_t &track = m_tracks[i]; if (!load_track(io, track, magic == OLD_FILE_MAGIC)) { clear_tape(); return false; @@ -77,17 +81,16 @@ bool hti_format_t::load_tape(util::random_read &io) void hti_format_t::save_tape(util::random_read_write &io) { - io.seek(0, SEEK_SET); + io.seek(0, SEEK_SET); // FIXME: check for errors - size_t actual; - uint8_t tmp[ 4 ]; + uint8_t tmp[4]; put_u32be(tmp, m_img_format == HTI_MANCHESTER_MOD ? FILE_MAGIC_MANCHESTER : FILE_MAGIC_DELTA); - io.write(tmp, 4, actual); + write(io, tmp, 4); // FIXME: check for errors for (unsigned i = 0; i < no_of_tracks(); i++) { - const tape_track_t& track = m_tracks[ i ]; - tape_pos_t next_pos = (tape_pos_t)-1; + const tape_track_t &track = m_tracks[i]; + tape_pos_t next_pos = tape_pos_t(-1); unsigned n_words = 0; tape_track_t::const_iterator it_start; for (tape_track_t::const_iterator it = track.cbegin(); it != track.cend(); ++it) { @@ -102,20 +105,20 @@ void hti_format_t::save_tape(util::random_read_write &io) dump_sequence(io, it_start, n_words); // End of track put_u32le(tmp, (uint32_t)-1); - io.write(tmp, 4, actual); + write(io, tmp, 4); // FIXME: check for errors } } void hti_format_t::clear_tape() { - for (tape_track_t& track : m_tracks) { + for (tape_track_t &track : m_tracks) { track.clear(); } } hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) const { - unsigned zeros , ones; + unsigned zeros, ones; // pop count of w ones = (w & 0x5555) + ((w >> 1) & 0x5555); @@ -128,7 +131,7 @@ hti_format_t::tape_pos_t hti_format_t::word_length(tape_word_t w) const return zeros * bit_length(false) + ones * bit_length(true); } -hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , bool forward) const +hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t &it, bool forward) const { if (forward) { return word_end_pos(it); @@ -137,7 +140,7 @@ hti_format_t::tape_pos_t hti_format_t::farthest_end(const track_iterator_t& it , } } -bool hti_format_t::pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset) +bool hti_format_t::pos_offset(tape_pos_t &pos, bool forward, tape_pos_t offset) { if (offset == 0) { return true; @@ -161,7 +164,7 @@ bool hti_format_t::pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset } } -hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) +hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos, bool forward) { if (forward) { for (tape_pos_t hole : tape_holes) { @@ -172,9 +175,9 @@ hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) // No more holes: will hit end of tape return NULL_TAPE_POS; } else { - for (int i = (sizeof(tape_holes) / sizeof(tape_holes[ 0 ])) - 1; i >= 0; i--) { - if (tape_holes[ i ] < pos) { - return tape_holes[ i ]; + for (int i = (sizeof(tape_holes) / sizeof(tape_holes[0])) - 1; i >= 0; i--) { + if (tape_holes[i] < pos) { + return tape_holes[i]; } } // No more holes: will hit start of tape @@ -182,16 +185,16 @@ hti_format_t::tape_pos_t hti_format_t::next_hole(tape_pos_t pos , bool forward) } } -void hti_format_t::write_word(unsigned track_no , tape_pos_t start , tape_word_t word , tape_pos_t& length , bool forward) +void hti_format_t::write_word(unsigned track_no, tape_pos_t start, tape_word_t word, tape_pos_t &length, bool forward) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(start); - adjust_it(track , it_low , start); + adjust_it(track, it_low, start); length = word_length(word); tape_pos_t end_pos = start + length; track_iterator_t it_high = track.lower_bound(end_pos); - track.erase(it_low , it_high); + track.erase(it_low, it_high); // A 0 word is inserted after the word being written, if space allows. // This is meant to avoid fragmentation of the slack space at the end of a record @@ -203,24 +206,24 @@ void hti_format_t::write_word(unsigned track_no , tape_pos_t start , tape_word_t it_high--; } - track.insert(it_high , std::make_pair(start, word)); + track.insert(it_high, std::make_pair(start, word)); } -void hti_format_t::write_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) +void hti_format_t::write_gap(unsigned track_no, tape_pos_t a, tape_pos_t b) { - ensure_a_lt_b(a , b); - tape_track_t& track = m_tracks[ track_no ]; + ensure_a_lt_b(a, b); + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(a); - adjust_it(track , it_low , a); + adjust_it(track, it_low, a); track_iterator_t it_high = track.lower_bound(b); track.erase(it_low, it_high); } -bool hti_format_t::just_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) +bool hti_format_t::just_gap(unsigned track_no, tape_pos_t a, tape_pos_t b) { - ensure_a_lt_b(a , b); - tape_track_t& track = m_tracks[ track_no ]; + ensure_a_lt_b(a, b); + tape_track_t &track = m_tracks[track_no]; track_iterator_t it_low = track.lower_bound(a); track_iterator_t it_high = track.lower_bound(b); @@ -229,9 +232,9 @@ bool hti_format_t::just_gap(unsigned track_no , tape_pos_t a , tape_pos_t b) return it_low == it_high; } -bool hti_format_t::next_data(unsigned track_no , tape_pos_t pos , bool forward , bool inclusive , track_iterator_t& it) +bool hti_format_t::next_data(unsigned track_no, tape_pos_t pos, bool forward, bool inclusive, track_iterator_t &it) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; it = track.lower_bound(pos); if (forward) { if (inclusive) { @@ -251,9 +254,9 @@ bool hti_format_t::next_data(unsigned track_no , tape_pos_t pos , bool forward , } } -hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no , bool forward , track_iterator_t& it) +hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no, bool forward, track_iterator_t &it) { - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; if (forward) { tape_pos_t prev_pos = word_end_pos(it); ++it; @@ -275,7 +278,7 @@ hti_format_t::adv_res_t hti_format_t::adv_it(unsigned track_no , bool forward , } } -bool hti_format_t::sync_with_record(unsigned track_no , track_iterator_t& it , unsigned& bit_idx) +bool hti_format_t::sync_with_record(unsigned track_no, track_iterator_t &it, unsigned &bit_idx) { while ((it->second & (1U << bit_idx)) == 0) { if (bit_idx) { @@ -296,7 +299,7 @@ bool hti_format_t::sync_with_record(unsigned track_no , track_iterator_t& it , u return true; } -hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no , track_iterator_t& it , unsigned& bit_idx , tape_word_t& word) +hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no, track_iterator_t &it, unsigned &bit_idx, tape_word_t &word) { if (bit_idx == 15) { auto res = adv_it(track_no, true, it); @@ -319,13 +322,13 @@ hti_format_t::adv_res_t hti_format_t::next_word(unsigned track_no , track_iterat } } -bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , tape_pos_t min_gap) +bool hti_format_t::next_gap(unsigned track_no, tape_pos_t &pos, bool forward, tape_pos_t min_gap) { tape_track_t::iterator it; // First align with next data - next_data(track_no , pos , forward , true , it); + next_data(track_no, pos, forward, true, it); // Then scan for 1st gap - tape_track_t& track = m_tracks[ track_no ]; + tape_track_t &track = m_tracks[track_no]; bool done = false; track_iterator_t prev_it; unsigned n_gaps = 1; @@ -346,7 +349,7 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , adv_res_t adv_res; do { prev_it = it; - adv_res = adv_it(track_no , forward , it); + adv_res = adv_it(track_no, forward, it); } while (adv_res == ADV_CONT_DATA); pos = word_end_pos(prev_it); } @@ -366,32 +369,36 @@ bool hti_format_t::next_gap(unsigned track_no , tape_pos_t& pos , bool forward , adv_res_t adv_res; do { prev_it = it; - adv_res = adv_it(track_no , forward , it); + adv_res = adv_it(track_no, forward, it); } while (adv_res == ADV_CONT_DATA); pos = prev_it->first; } } // Set "pos" where minimum gap size is met - pos_offset(pos , forward , min_gap); + pos_offset(pos, forward, min_gap); return n_gaps == 0; } -bool hti_format_t::load_track(util::random_read &io , 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; tape_pos_t last_word_end = 0; track.clear(); while (1) { - // Read no. of words to follow - io.read(tmp, 4, actual); + std::error_condition err; + size_t actual; + uint8_t tmp[4]; + uint32_t tmp32; + // Read no. of words to follow + std::tie(err, actual) = read(io, tmp, 4); + if (err || (4 != actual)) { + return false; + } tmp32 = get_u32le(tmp); // Track ends @@ -402,8 +409,10 @@ bool hti_format_t::load_track(util::random_read &io , tape_track_t& track , bool unsigned n_words = tmp32; // Read tape position of block - io.read(tmp, 4, actual); - + std::tie(err, actual) = read(io, tmp, 4); + if (err || (4 != actual)) { + return false; + } tmp32 = get_u32le(tmp); tape_pos_t pos = (tape_pos_t)tmp32 + delta_pos; @@ -414,11 +423,14 @@ bool hti_format_t::load_track(util::random_read &io , tape_track_t& track , bool for (unsigned i = 0; i < n_words; i++) { uint16_t tmp16; - io.read(tmp, 2, actual); + std::tie(err, actual) = read(io, tmp, 2); + if (err || (2 != actual)) { + return false; + } tmp16 = get_u16le(tmp); if (!old_format) { - track.insert(std::make_pair(pos , tmp16)); + track.insert(std::make_pair(pos, tmp16)); pos += word_length(tmp16); } else if (m_img_format == HTI_DELTA_MOD_16_BITS) { // Convert HP9845 & HP85 old format @@ -471,29 +483,28 @@ bool hti_format_t::load_track(util::random_read &io , tape_track_t& track , bool } } -void hti_format_t::dump_sequence(util::random_read_write &io , 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 ]; - put_u32le(&tmp[ 0 ], n_words); - put_u32le(&tmp[ 4 ], it_start->first); - io.write(tmp, 8, actual); + uint8_t tmp[8]; + put_u32le(&tmp[0], n_words); + put_u32le(&tmp[4], it_start->first); + write(io, tmp, 8); // FIXME: check for errors for (unsigned i = 0; i < n_words; i++) { put_u16le(tmp, it_start->second); - io.write(tmp, 2, actual); + write(io, tmp, 2); // FIXME: check for errors ++it_start; } } } -hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t& it) const +hti_format_t::tape_pos_t hti_format_t::word_end_pos(const track_iterator_t &it) const { return it->first + word_length(it->second); } -void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_pos_t pos) const +void hti_format_t::adjust_it(tape_track_t &track, track_iterator_t &it, tape_pos_t pos) const { if (it != track.begin()) { --it; @@ -503,7 +514,7 @@ void hti_format_t::adjust_it(tape_track_t& track , track_iterator_t& it , tape_p } } -void hti_format_t::ensure_a_lt_b(tape_pos_t& a , tape_pos_t& b) +void hti_format_t::ensure_a_lt_b(tape_pos_t &a, tape_pos_t &b) { if (a > b) { // Ensure A always comes before B diff --git a/src/lib/formats/hti_tape.h b/src/lib/formats/hti_tape.h index 373c971d174..d343133583f 100644 --- a/src/lib/formats/hti_tape.h +++ b/src/lib/formats/hti_tape.h @@ -22,8 +22,6 @@ class hti_format_t { public: - hti_format_t(); - // Tape position, 1 unit = 1 inch / (968 * 1024) typedef int32_t tape_pos_t; @@ -55,7 +53,6 @@ public: // Iterator to access words on tape typedef tape_track_t::iterator track_iterator_t; - // Set image format enum image_format_t { // Delta modulation, 16 bits per word, 2 tracks per cartridge // HP 9845 & HP 85 @@ -68,6 +65,16 @@ public: HTI_MANCHESTER_MOD }; + enum adv_res_t + { + ADV_NO_MORE_DATA, + ADV_CONT_DATA, + ADV_DISCONT_DATA + }; + + hti_format_t(); + + // Set image format void set_image_format(image_format_t fmt) { m_img_format = fmt; } // Return number of tracks @@ -86,55 +93,48 @@ public: // Return physical length of a 16-bit word on tape tape_pos_t word_length(tape_word_t w) const; - tape_pos_t farthest_end(const track_iterator_t& it , bool forward) const; + tape_pos_t farthest_end(const track_iterator_t &it, bool forward) const; - static bool pos_offset(tape_pos_t& pos , bool forward , tape_pos_t offset); + static bool pos_offset(tape_pos_t &pos, bool forward, tape_pos_t offset); // Position of next hole tape will reach in a given direction - static tape_pos_t next_hole(tape_pos_t pos , bool forward); + static tape_pos_t next_hole(tape_pos_t pos, bool forward); // Write a data word on tape - void write_word(unsigned track_no , tape_pos_t start , tape_word_t word , tape_pos_t& length , bool forward = true); + void write_word(unsigned track_no, tape_pos_t start, tape_word_t word, tape_pos_t &length, bool forward = true); // Write a gap on tape - void write_gap(unsigned track_no , tape_pos_t a , tape_pos_t b); + void write_gap(unsigned track_no, tape_pos_t a, tape_pos_t b); // Check that a section of tape has no data (it's just gap) - bool just_gap(unsigned track_no , tape_pos_t a , tape_pos_t b); + bool just_gap(unsigned track_no, tape_pos_t a, tape_pos_t b); // Return position of next data word in a given direction - bool next_data(unsigned track_no , tape_pos_t pos , bool forward , bool inclusive , track_iterator_t& it); - - enum adv_res_t - { - ADV_NO_MORE_DATA, - ADV_CONT_DATA, - ADV_DISCONT_DATA - }; + bool next_data(unsigned track_no, tape_pos_t pos, bool forward, bool inclusive, track_iterator_t &it); // Advance an iterator to next word of data - adv_res_t adv_it(unsigned track_no , bool forward , track_iterator_t& it); + adv_res_t adv_it(unsigned track_no, bool forward, track_iterator_t &it); // Sync with the preamble of a record - bool sync_with_record(unsigned track_no , track_iterator_t& it , unsigned& bit_idx); + bool sync_with_record(unsigned track_no, track_iterator_t &it, unsigned &bit_idx); // Get a data word from record, after syncing - adv_res_t next_word(unsigned track_no , track_iterator_t& it , unsigned& bit_idx , tape_word_t& word); + adv_res_t next_word(unsigned track_no, track_iterator_t &it, unsigned &bit_idx, tape_word_t &word); // Scan for beginning of next gap in a given direction - bool next_gap(unsigned track_no , tape_pos_t& pos , bool forward , tape_pos_t min_gap); + bool next_gap(unsigned track_no, tape_pos_t &pos, bool forward, tape_pos_t min_gap); private: // Content of tape tracks - tape_track_t m_tracks[ 2 ]; + tape_track_t m_tracks[2]; // Image format image_format_t m_img_format; - 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); + 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; - static void ensure_a_lt_b(tape_pos_t& a , tape_pos_t& b); + 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; + static void ensure_a_lt_b(tape_pos_t &a, tape_pos_t &b); }; #endif // MAME_FORMATS_HTI_TAPE_H diff --git a/src/lib/formats/hxchfe_dsk.cpp b/src/lib/formats/hxchfe_dsk.cpp index a8cf09feaf2..da8d660bb33 100644 --- a/src/lib/formats/hxchfe_dsk.cpp +++ b/src/lib/formats/hxchfe_dsk.cpp @@ -106,6 +106,8 @@ #include "osdcore.h" // osd_printf_* +#include <tuple> + #define HFE_FORMAT_HEADER "HXCPICFE" @@ -139,10 +141,11 @@ bool hfe_format::supports_save() const noexcept int hfe_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[8]; - - size_t actual; - io.read_at(0, &header, sizeof(header), actual); - if ( memcmp( header, HFE_FORMAT_HEADER, 8 ) ==0) { + auto const [err, actual] = read_at(io, 0, &header, sizeof(header)); + if (err || (sizeof(header) != actual)) { + return 0; + } + if (!memcmp(header, HFE_FORMAT_HEADER, 8)) { return FIFID_SIGN; } return 0; @@ -150,16 +153,15 @@ int hfe_format::identify(util::random_read &io, uint32_t form_factor, const std: bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; - uint8_t header[HEADER_LENGTH]; - uint8_t track_table[TRACK_TABLE_LENGTH]; - header_info info; int drivecyl, driveheads; image.get_maximal_geometry(drivecyl, driveheads); // read header - io.read_at(0, header, HEADER_LENGTH, actual); + uint8_t header[HEADER_LENGTH]; + std::tie(err, actual) = read_at(io, 0, header, HEADER_LENGTH); // FIXME: check for errors and premature EOF // get values // Format revision must be 0 @@ -169,6 +171,7 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; } + header_info info; info.m_cylinders = header[9] & 0xff; info.m_heads = header[10] & 0xff; @@ -194,7 +197,7 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; } - info.m_track_encoding = (encoding_t)(header[11] & 0xff); + info.m_track_encoding = encoding_t(header[11] & 0xff); if (info.m_track_encoding > EMU_FM_ENCODING) { @@ -231,7 +234,8 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve // read track lookup table (multiple of 512) int table_offset = get_u16le(&header[18]); - io.read_at(table_offset<<9, track_table, TRACK_TABLE_LENGTH, actual); + uint8_t track_table[TRACK_TABLE_LENGTH]; + std::tie(err, actual) = read_at(io, table_offset<<9, track_table, TRACK_TABLE_LENGTH); // FIXME: check for errors and premature EOF for (int i=0; i < info.m_cylinders; i++) { @@ -244,10 +248,9 @@ bool hfe_format::load(util::random_read &io, uint32_t form_factor, const std::ve for(int cyl=0; cyl < info.m_cylinders; cyl++) { // actual data read - // The HFE format defines an interleave of the two sides per cylinder - // at every 256 bytes + // The HFE format defines an interleave of the two sides per cylinder at every 256 bytes cylinder_buffer.resize(info.m_cyl_length[cyl]); - io.read_at(info.m_cyl_offset[cyl]<<9, &cylinder_buffer[0], info.m_cyl_length[cyl], actual); + std::tie(err, actual) = read_at(io, info.m_cyl_offset[cyl]<<9, &cylinder_buffer[0], info.m_cyl_length[cyl]); // FIXME: check for errors and premature EOF generate_track_from_hfe_bitstream(cyl, 0, samplelength, &cylinder_buffer[0], info.m_cyl_length[cyl], image); if (info.m_heads == 2) diff --git a/src/lib/formats/hxcmfm_dsk.cpp b/src/lib/formats/hxcmfm_dsk.cpp index 0390b55bca0..d9fda047dea 100644 --- a/src/lib/formats/hxcmfm_dsk.cpp +++ b/src/lib/formats/hxcmfm_dsk.cpp @@ -6,6 +6,7 @@ #include "ioprocs.h" #include <cstring> +#include <tuple> #define MFM_FORMAT_HEADER "HXCMFM" @@ -63,10 +64,11 @@ bool mfm_format::supports_save() const noexcept int mfm_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t header[7]; - - size_t actual; - io.read_at(0, &header, sizeof(header), actual); - if ( memcmp( header, MFM_FORMAT_HEADER, 6 ) ==0) { + auto const [err, actual] = read_at(io, 0, &header, sizeof(header)); // FIXME: does this really need to read 7 bytes? only 6 are checked. also check for premature EOF + if (err) { + return 0; + } + if (!memcmp(header, MFM_FORMAT_HEADER, 6)) { return FIFID_SIGN; } return 0; @@ -74,12 +76,13 @@ int mfm_format::identify(util::random_read &io, uint32_t form_factor, const std: bool mfm_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; MFMIMG header; MFMTRACKIMG trackdesc; // read header - io.read_at(0, &header, sizeof(header), actual); + std::tie(err, actual) = read_at(io, 0, &header, sizeof(header)); // FIXME: check for errors and premature EOF int drivecyl, driveheads; image.get_maximal_geometry(drivecyl, driveheads); @@ -91,12 +94,12 @@ bool mfm_format::load(util::random_read &io, uint32_t form_factor, const std::ve for(int side=0; side < header.number_of_side; side++) { if (!skip_odd || track%2 == 0) { // read location of - io.read_at((header.mfmtracklistoffset)+( counter *sizeof(trackdesc)), &trackdesc, sizeof(trackdesc), actual); + std::tie(err, actual) = read_at(io, header.mfmtracklistoffset + (counter * sizeof(trackdesc)), &trackdesc, sizeof(trackdesc)); // FIXME: check for errors and premature EOF trackbuf.resize(trackdesc.mfmtracksize); // actual data read - io.read_at(trackdesc.mfmtrackoffset, &trackbuf[0], trackdesc.mfmtracksize, actual); + std::tie(err, actual) = read_at(io, trackdesc.mfmtrackoffset, &trackbuf[0], trackdesc.mfmtracksize); // FIXME: check for errors and premature EOF if (skip_odd) { generate_track_from_bitstream(track/2, side, &trackbuf[0], trackdesc.mfmtracksize*8, image); @@ -117,7 +120,6 @@ bool mfm_format::load(util::random_read &io, uint32_t form_factor, const std::ve bool mfm_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { // TODO: HD support - size_t actual; MFMIMG header; int track_count, head_count; image.get_actual_geometry(track_count, head_count); @@ -130,7 +132,7 @@ bool mfm_format::save(util::random_read_write &io, const std::vector<uint32_t> & header.floppyiftype = 4; header.mfmtracklistoffset = sizeof(MFMIMG); - io.write_at(0, &header, sizeof(MFMIMG), actual); + write_at(io, 0, &header, sizeof(MFMIMG)); // FIXME: check for errors int tpos = sizeof(MFMIMG); int dpos = tpos + track_count*head_count*sizeof(MFMTRACKIMG); @@ -149,8 +151,8 @@ bool mfm_format::save(util::random_read_write &io, const std::vector<uint32_t> & trackdesc.mfmtracksize = packed.size(); trackdesc.mfmtrackoffset = dpos; - io.write_at(tpos, &trackdesc, sizeof(MFMTRACKIMG), actual); - io.write_at(dpos, packed.data(), packed.size(), actual); + write_at(io, tpos, &trackdesc, sizeof(MFMTRACKIMG)); // FIXME: check for errors + write_at(io, dpos, packed.data(), packed.size()); // FIXME: check for errors tpos += sizeof(MFMTRACKIMG); dpos += packed.size(); diff --git a/src/lib/formats/ibmxdf_dsk.cpp b/src/lib/formats/ibmxdf_dsk.cpp index 5fb1f3da411..c9704361f65 100644 --- a/src/lib/formats/ibmxdf_dsk.cpp +++ b/src/lib/formats/ibmxdf_dsk.cpp @@ -186,8 +186,8 @@ bool ibmxdf_format::load(util::random_read &io, uint32_t form_factor, const std: const format &f = formats[type]; - for(int track=0; track < f.track_count; track++) - for(int head=0; head < f.head_count; head++) { + for(int track = 0; track < f.track_count; track++) { + for(int head = 0; head < f.head_count; head++) { uint8_t sectdata[23 * 2 * 512]; // XXX magic desc_s sectors[40]; floppy_image_format_t::desc_e *desc; @@ -213,10 +213,10 @@ bool ibmxdf_format::load(util::random_read &io, uint32_t form_factor, const std: build_sector_description(tf, sectdata, sectors, track, head); 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); + /*auto const [err, actual] =*/ read_at(io, get_image_offset(f, head, track), sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(desc, track, head, sectors, tf.sector_count, total_size, image); } + } image.set_variant(f.variant); diff --git a/src/lib/formats/idpart_dsk.cpp b/src/lib/formats/idpart_dsk.cpp new file mode 100644 index 00000000000..9d4c641fa41 --- /dev/null +++ b/src/lib/formats/idpart_dsk.cpp @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************* + + formats/idpart_dsk.cpp + + Iskra Delta Partner format + +*********************************************************************/ + +#include "formats/idpart_dsk.h" + +idpart_format::idpart_format() : upd765_format(formats) +{ +} + +const char *idpart_format::name() const noexcept +{ + return "idpart"; +} + +const char *idpart_format::description() const noexcept +{ + return "Iskra Delta Partner disk image"; +} + +const char *idpart_format::extensions() const noexcept +{ + return "img"; +} + +// Unverified gap sizes. +const idpart_format::format idpart_format::formats[] = { + { + floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM, + 2000, + 18, 73, 2, + 256, {}, + 1, {}, + 80, 50, 22 + }, + { + floppy_image::FF_525, floppy_image::DSQD, floppy_image::MFM, + 2000, + 18, 77, 2, + 256, {}, + 1, {}, + 80, 50, 22 + }, + {} +}; + +const idpart_format FLOPPY_IDPART_FORMAT; diff --git a/src/lib/formats/idpart_dsk.h b/src/lib/formats/idpart_dsk.h new file mode 100644 index 00000000000..6f5977a5cfa --- /dev/null +++ b/src/lib/formats/idpart_dsk.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************* + + formats/idpart_dsk.h + + Iskra Delta Partner format + +*********************************************************************/ +#ifndef MAME_FORMATS_IDPART_DSK_H +#define MAME_FORMATS_IDPART_DSK_H + +#pragma once + +#include "upd765_dsk.h" + +class idpart_format : public upd765_format +{ +public: + idpart_format(); + + virtual const char *name() const noexcept override; + virtual const char *description() const noexcept override; + virtual const char *extensions() const noexcept override; + +private: + static const format formats[]; +}; + +extern const idpart_format FLOPPY_IDPART_FORMAT; + +#endif // MAME_FORMATS_IDPART_DSK_H diff --git a/src/lib/formats/imd_dsk.cpp b/src/lib/formats/imd_dsk.cpp index fde013f3113..907440dc922 100644 --- a/src/lib/formats/imd_dsk.cpp +++ b/src/lib/formats/imd_dsk.cpp @@ -425,9 +425,10 @@ void imd_format::fixnum(char *start, char *end) const int imd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { char h[4]; + auto const [err, actual] = read_at(io, 0, h, 4); + if(err || (4 != actual)) + return 0; - size_t actual; - io.read_at(0, h, 4, actual); if(!memcmp(h, "IMD ", 4)) return FIFID_SIGN; @@ -451,9 +452,9 @@ bool imd_format::load(util::random_read &io, uint32_t form_factor, const std::ve uint64_t size; if(io.length(size)) return false; - std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [err, img, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return false; uint64_t pos, savepos; for(pos=0; pos < size && img[pos] != 0x1a; pos++) { } diff --git a/src/lib/formats/img_dsk.cpp b/src/lib/formats/img_dsk.cpp index fb6f1a3bfb3..66e097c281e 100644 --- a/src/lib/formats/img_dsk.cpp +++ b/src/lib/formats/img_dsk.cpp @@ -72,9 +72,10 @@ bool img_format::load(util::random_read &io, uint32_t form_factor, const std::ve image.set_variant(is_dd ? floppy_image::SSDD : floppy_image::SSSD); // Suck in the whole image - std::vector<uint8_t> image_data(size); - size_t actual; - io.read_at(0, image_data.data(), size, actual); + auto const [err, image_data, actual] = read_at(io, 0, size); + if (err || (actual != size)) { + return false; + } for (unsigned cyl = 0; cyl < TRACKS; cyl++) { if (is_dd) { @@ -134,7 +135,7 @@ bool img_format::load(util::random_read &io, uint32_t form_factor, const std::ve sects[ sector ].sector = real_sector; sects[ sector ].bad_crc = false; sects[ sector ].deleted = false; - sects[ sector ].data = image_data.data() + offset_in_image; + sects[ sector ].data = &image_data[offset_in_image]; } build_pc_track_fm(cyl, 0, image, 83333, SECTORS_FM, sects, 33, 46, 32, 11); } @@ -155,8 +156,7 @@ bool img_format::save(util::random_read_write &io, const std::vector<uint32_t> & 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; - size_t actual; - io.write_at(offset_in_image, sector_data, SECTOR_SIZE, actual); + /*auto const [err, actual] =*/ write_at(io, offset_in_image, sector_data, SECTOR_SIZE); // FIXME: check for errors } } } else { @@ -164,8 +164,7 @@ bool img_format::save(util::random_read_write &io, const std::vector<uint32_t> & auto sects = extract_sectors_from_bitstream_fm_pc(bitstream); for (unsigned s = 1; s <= SECTORS_FM; s++) { unsigned offset_in_image = (cyl * SECTORS_FM + s - 1) * SECTOR_SIZE; - size_t actual; - io.write_at(offset_in_image, sects[ s ].data(), SECTOR_SIZE, actual); + /*auto const [err, actual] =*/ write_at(io, offset_in_image, sects[ s ].data(), SECTOR_SIZE); // FIXME: check for errors and premature EOF } } } diff --git a/src/lib/formats/ipf_dsk.cpp b/src/lib/formats/ipf_dsk.cpp index 072dd96c99e..b47eca030f2 100644 --- a/src/lib/formats/ipf_dsk.cpp +++ b/src/lib/formats/ipf_dsk.cpp @@ -8,6 +8,72 @@ #include <cstring> +struct ipf_format::ipf_decode { + struct track_info { + uint32_t cylinder = 0, head = 0, type = 0; + uint32_t sigtype = 0, process = 0, reserved[3] = { 0, 0, 0 }; + uint32_t size_bytes = 0, size_cells = 0; + uint32_t index_bytes = 0, index_cells = 0; + uint32_t datasize_cells = 0, gapsize_cells = 0; + uint32_t block_count = 0, weak_bits = 0; + + uint32_t data_size_bits = 0; + + bool info_set = false; + + const uint8_t *data = nullptr; + uint32_t data_size = 0; + }; + + std::vector<track_info> tinfos; + uint32_t tcount = 0; + + uint32_t type = 0, release = 0, revision = 0; + uint32_t encoder_type = 0, encoder_revision = 0, origin = 0; + uint32_t min_cylinder = 0, max_cylinder = 0, min_head = 0, max_head = 0; + uint32_t credit_day = 0, credit_time = 0; + uint32_t platform[4] = {}, extra[5] = {}; + + uint32_t crc32r(const uint8_t *data, uint32_t size); + + bool parse_info(const uint8_t *info); + bool parse_imge(const uint8_t *imge); + bool parse_data(const uint8_t *data, uint32_t &pos, uint32_t max_extra_size); + + bool scan_one_tag(uint8_t *data, size_t size, uint32_t &pos, uint8_t *&tag, uint32_t &tsize); + bool scan_all_tags(uint8_t *data, size_t size); + static uint32_t rb(const uint8_t *&p, int count); + + track_info *get_index(uint32_t idx); + + void track_write_raw(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t cells, bool &context); + void track_write_mfm(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t start_offset, uint32_t patlen, uint32_t cells, bool &context); + void track_write_weak(std::vector<uint32_t>::iterator &tpos, uint32_t cells); + bool generate_block_data(const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, std::vector<uint32_t>::iterator tlimit, bool &context); + + bool gap_description_to_reserved_size(const uint8_t *&data, const uint8_t *dlimit, uint32_t &res_size); + bool generate_gap_from_description(const uint8_t *&data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, uint32_t size, bool pre, bool &context); + bool generate_block_gap_0(uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, std::vector<uint32_t>::iterator &tpos, bool &context); + bool generate_block_gap_1(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); + bool generate_block_gap_2(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); + bool generate_block_gap_3(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); + bool generate_block_gap(uint32_t gap_type, uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, bool &context); + + bool generate_block(const track_info &t, uint32_t idx, uint32_t ipos, std::vector<uint32_t> &track, uint32_t &pos, uint32_t &dpos, uint32_t &gpos, uint32_t &spos, bool &context); + uint32_t block_compute_real_size(const track_info &t); + + void timing_set(std::vector<uint32_t> &track, uint32_t start, uint32_t end, uint32_t time); + bool generate_timings(const track_info &t, std::vector<uint32_t> &track, const std::vector<uint32_t> &data_pos, const std::vector<uint32_t> &gap_pos); + + void rotate(std::vector<uint32_t> &track, uint32_t offset, uint32_t size); + void mark_track_splice(std::vector<uint32_t> &track, uint32_t offset, uint32_t size); + bool generate_track(track_info &t, floppy_image &image); + bool generate_tracks(floppy_image &image); + + bool parse(uint8_t *data, size_t size, floppy_image &image); +}; + + const ipf_format FLOPPY_IPF_FORMAT; const char *ipf_format::name() const noexcept @@ -34,8 +100,9 @@ int ipf_format::identify(util::random_read &io, uint32_t form_factor, const std: { static const uint8_t refh[12] = { 0x43, 0x41, 0x50, 0x53, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0xd5, 0x73, 0xba }; uint8_t h[12]; - size_t actual; - io.read_at(0, h, 12, actual); + auto const [err, actual] = read_at(io, 0, h, 12); + if(err || (12 != actual)) + return 0; if(!memcmp(h, refh, 12)) return FIFID_SIGN; @@ -46,13 +113,13 @@ int ipf_format::identify(util::random_read &io, uint32_t form_factor, const std: bool ipf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { uint64_t size; - if (io.length(size)) + if(io.length(size)) + return false; + auto const [err, data, actual] = read_at(io, 0, size); + if(err || (actual != size)) return false; - std::vector<uint8_t> data(size); - size_t actual; - io.read_at(0, &data[0], size, actual); ipf_decode dec; - return dec.parse(data, image); + return dec.parse(data.get(), size, image); } @@ -79,12 +146,12 @@ uint32_t ipf_format::ipf_decode::crc32r(const uint8_t *data, uint32_t size) return ~crc; } -bool ipf_format::ipf_decode::parse(std::vector<uint8_t> &data, floppy_image &image) +bool ipf_format::ipf_decode::parse(uint8_t *data, size_t size, floppy_image &image) { image.set_variant(floppy_image::DSDD); // Not handling anything else yet tcount = 84*2+1; // Usual max tinfos.resize(tcount); - bool res = scan_all_tags(data); + bool res = scan_all_tags(data, size); if(res) res = generate_tracks(image); tinfos.clear(); @@ -177,13 +244,13 @@ bool ipf_format::ipf_decode::parse_data(const uint8_t *data, uint32_t &pos, uint return true; } -bool ipf_format::ipf_decode::scan_one_tag(std::vector<uint8_t> &data, uint32_t &pos, uint8_t *&tag, uint32_t &tsize) +bool ipf_format::ipf_decode::scan_one_tag(uint8_t *data, size_t size, uint32_t &pos, uint8_t *&tag, uint32_t &tsize) { - if(data.size()-pos < 12) + if(size-pos < 12) return false; tag = &data[pos]; tsize = get_u32be(tag+4); - if(data.size()-pos < tsize) + if(size-pos < tsize) return false; uint32_t crc = get_u32be(tag+8); tag[8] = tag[9] = tag[10] = tag[11] = 0; @@ -193,15 +260,14 @@ bool ipf_format::ipf_decode::scan_one_tag(std::vector<uint8_t> &data, uint32_t & return true; } -bool ipf_format::ipf_decode::scan_all_tags(std::vector<uint8_t> &data) +bool ipf_format::ipf_decode::scan_all_tags(uint8_t *data, size_t size) { uint32_t pos = 0; - uint32_t size = data.size(); while(pos != size) { uint8_t *tag; uint32_t tsize; - if(!scan_one_tag(data, pos, tag, tsize)) + if(!scan_one_tag(data, size, pos, tag, tsize)) return false; switch(get_u32be(tag)) { diff --git a/src/lib/formats/ipf_dsk.h b/src/lib/formats/ipf_dsk.h index 9e63b2bff38..a1c36f02f8d 100644 --- a/src/lib/formats/ipf_dsk.h +++ b/src/lib/formats/ipf_dsk.h @@ -21,71 +21,7 @@ public: virtual bool supports_save() const noexcept override; private: - struct ipf_decode { - struct track_info { - uint32_t cylinder = 0, head = 0, type = 0; - uint32_t sigtype = 0, process = 0, reserved[3] = { 0, 0, 0 }; - uint32_t size_bytes = 0, size_cells = 0; - uint32_t index_bytes = 0, index_cells = 0; - uint32_t datasize_cells = 0, gapsize_cells = 0; - uint32_t block_count = 0, weak_bits = 0; - - uint32_t data_size_bits = 0; - - bool info_set = false; - - const uint8_t *data = nullptr; - uint32_t data_size = 0; - }; - - std::vector<track_info> tinfos; - uint32_t tcount = 0; - - uint32_t type = 0, release = 0, revision = 0; - uint32_t encoder_type = 0, encoder_revision = 0, origin = 0; - uint32_t min_cylinder = 0, max_cylinder = 0, min_head = 0, max_head = 0; - uint32_t credit_day = 0, credit_time = 0; - uint32_t platform[4] = {}, extra[5] = {}; - - uint32_t crc32r(const uint8_t *data, uint32_t size); - - bool parse_info(const uint8_t *info); - bool parse_imge(const uint8_t *imge); - bool parse_data(const uint8_t *data, uint32_t &pos, uint32_t max_extra_size); - - bool scan_one_tag(std::vector<uint8_t> &data, uint32_t &pos, uint8_t *&tag, uint32_t &tsize); - bool scan_all_tags(std::vector<uint8_t> &data); - static uint32_t r32(const uint8_t *p); - static uint32_t rb(const uint8_t *&p, int count); - - track_info *get_index(uint32_t idx); - - void track_write_raw(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t cells, bool &context); - void track_write_mfm(std::vector<uint32_t>::iterator &tpos, const uint8_t *data, uint32_t start_offset, uint32_t patlen, uint32_t cells, bool &context); - void track_write_weak(std::vector<uint32_t>::iterator &tpos, uint32_t cells); - bool generate_block_data(const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, std::vector<uint32_t>::iterator tlimit, bool &context); - - bool gap_description_to_reserved_size(const uint8_t *&data, const uint8_t *dlimit, uint32_t &res_size); - bool generate_gap_from_description(const uint8_t *&data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, uint32_t size, bool pre, bool &context); - bool generate_block_gap_0(uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, std::vector<uint32_t>::iterator &tpos, bool &context); - bool generate_block_gap_1(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); - bool generate_block_gap_2(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); - bool generate_block_gap_3(uint32_t gap_cells, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator &tpos, bool &context); - bool generate_block_gap(uint32_t gap_type, uint32_t gap_cells, uint8_t pattern, uint32_t &spos, uint32_t ipos, const uint8_t *data, const uint8_t *dlimit, std::vector<uint32_t>::iterator tpos, bool &context); - - bool generate_block(const track_info &t, uint32_t idx, uint32_t ipos, std::vector<uint32_t> &track, uint32_t &pos, uint32_t &dpos, uint32_t &gpos, uint32_t &spos, bool &context); - uint32_t block_compute_real_size(const track_info &t); - - void timing_set(std::vector<uint32_t> &track, uint32_t start, uint32_t end, uint32_t time); - bool generate_timings(const track_info &t, std::vector<uint32_t> &track, const std::vector<uint32_t> &data_pos, const std::vector<uint32_t> &gap_pos); - - void rotate(std::vector<uint32_t> &track, uint32_t offset, uint32_t size); - void mark_track_splice(std::vector<uint32_t> &track, uint32_t offset, uint32_t size); - bool generate_track(track_info &t, floppy_image &image); - bool generate_tracks(floppy_image &image); - - bool parse(std::vector<uint8_t> &data, floppy_image &image); - }; + struct ipf_decode; }; extern const ipf_format FLOPPY_IPF_FORMAT; diff --git a/src/lib/formats/jfd_dsk.cpp b/src/lib/formats/jfd_dsk.cpp index 813c7192ca9..46e933cedf1 100644 --- a/src/lib/formats/jfd_dsk.cpp +++ b/src/lib/formats/jfd_dsk.cpp @@ -197,8 +197,9 @@ int jfd_format::identify(util::random_read &io, uint32_t form_factor, const std: return 0; std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [ioerr, actual] = read_at(io, 0, &img[0], size); + if (ioerr || (actual != size)) + return 0; int err; std::vector<uint8_t> gz_ptr(4); @@ -222,7 +223,7 @@ int jfd_format::identify(util::random_read &io, uint32_t form_factor, const std: err = inflateEnd(&d_stream); if (err != Z_OK) return 0; - img = gz_ptr; + img = std::move(gz_ptr); } if (!memcmp(&img[0], JFD_HEADER, sizeof(JFD_HEADER))) { @@ -239,8 +240,9 @@ bool jfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; std::vector<uint8_t> img(size); - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [ioerr, actual] = read_at(io, 0, &img[0], size); + if (ioerr || (actual != size)) + return false; int err; std::vector<uint8_t> gz_ptr; @@ -274,7 +276,7 @@ bool jfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve return false; } size = inflate_size; - img = gz_ptr; + img = std::move(gz_ptr); } osd_printf_verbose("jfd_dsk: loading %s\n", &img[48]); diff --git a/src/lib/formats/juku_dsk.cpp b/src/lib/formats/juku_dsk.cpp index 05fdc9b8484..46d448a2c61 100644 --- a/src/lib/formats/juku_dsk.cpp +++ b/src/lib/formats/juku_dsk.cpp @@ -1,8 +1,8 @@ // license: BSD-3-Clause -// copyright-holders: Dirk Best +// copyright-holders: Dirk Best, Märt Põder /*************************************************************************** - Juku E5101 + Juku E5101/E5104 Disk image format @@ -31,11 +31,11 @@ const char *juku_format::extensions() const noexcept const juku_format::format juku_format::formats[] = { - { // 800k 5 1/4 inch double density single sided - gaps unverified (CP/M) - floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM, + { // 386k 5.25" double density single sided - gaps unverified (CP/M) + floppy_image::FF_525, floppy_image::SSDD, floppy_image::MFM, 2000, 10, 80, 1, 512, {}, 1, {}, 32, 22, 35 }, - { // 800k 5 1/4 inch double density double sided - gaps unverified (CP/M) + { // 786k 5.25" double density "outout" double sided - gaps unverified (CP/M) floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM, 2000, 10, 80, 2, 512, {}, 1, {}, 32, 22, 35 }, diff --git a/src/lib/formats/juku_dsk.h b/src/lib/formats/juku_dsk.h index 414c351ac76..c78363ece14 100644 --- a/src/lib/formats/juku_dsk.h +++ b/src/lib/formats/juku_dsk.h @@ -1,8 +1,8 @@ // license: BSD-3-Clause -// copyright-holders: Dirk Best +// copyright-holders: Dirk Best, Märt Põder /*************************************************************************** - Juku E5101 + Juku E5101/E5104 Disk image format diff --git a/src/lib/formats/jvc_dsk.cpp b/src/lib/formats/jvc_dsk.cpp index ce0083a9deb..fcc5d97a5b5 100644 --- a/src/lib/formats/jvc_dsk.cpp +++ b/src/lib/formats/jvc_dsk.cpp @@ -141,11 +141,14 @@ bool jvc_format::parse_header(util::random_read &io, int &header_size, int &trac 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)) + if (header_size >= sizeof(header)) // TODO: wouldn't this make more sense with > than >=? The first case in the following switch statement is unreachable as-is. return false; if (header_size > 0) - io.read_at(0, header, header_size, actual); + { + auto const [err, actual] = read_at(io, 0, header, header_size); + if (err || (actual != header_size)) + return false; + } // default values heads = 1; @@ -241,8 +244,7 @@ bool jvc_format::load(util::random_read &io, uint32_t form_factor, const std::ve sectors[interleave[i]].bad_crc = false; sectors[interleave[i]].data = §or_data[sector_offset]; - size_t actual; - io.read_at(file_offset, sectors[interleave[i]].data, sector_size, actual); + /*auto const [err, actual] =*/ read_at(io, file_offset, sectors[interleave[i]].data, sector_size); // FIXME: check for errors and premature EOF sector_offset += sector_size; file_offset += sector_size; @@ -268,8 +270,7 @@ bool jvc_format::save(util::random_read_write &io, const std::vector<uint32_t> & uint8_t header[2]; header[0] = 18; header[1] = 2; - size_t actual; - io.write_at(file_offset, header, sizeof(header), actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, header, sizeof(header)); // FIXME: check for errors file_offset += sizeof(header); } @@ -289,8 +290,7 @@ bool jvc_format::save(util::random_read_write &io, const std::vector<uint32_t> & return false; } - size_t actual; - io.write_at(file_offset, sectors[1 + i].data(), 256, actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, sectors[1 + i].data(), 256); // FIXME: check for errors file_offset += 256; } } diff --git a/src/lib/formats/kc_cas.cpp b/src/lib/formats/kc_cas.cpp index 035d18fb4cd..34c52786b9c 100644 --- a/src/lib/formats/kc_cas.cpp +++ b/src/lib/formats/kc_cas.cpp @@ -232,7 +232,7 @@ static int kc_handle_sss(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int kc_kcc_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int kc_kcc_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return kc_handle_kcc(buffer, bytes); } @@ -243,7 +243,7 @@ static int kc_kcc_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) ********************************************************************/ static int kc_kcc_to_wav_size(const uint8_t *casdata, int caslen) { - kc_image_size = caslen ; + kc_image_size = caslen; return kc_handle_kcc( nullptr, casdata ); } @@ -284,7 +284,7 @@ static const cassette_image::Format kc_kcc_format = /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int kc_tap_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int kc_tap_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return kc_handle_tap(buffer, bytes); } @@ -295,7 +295,7 @@ static int kc_tap_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) ********************************************************************/ static int kc_tap_to_wav_size(const uint8_t *casdata, int caslen) { - kc_image_size = caslen ; + kc_image_size = caslen; return kc_handle_tap( nullptr, casdata ); } @@ -336,7 +336,7 @@ static const cassette_image::Format kc_tap_format = /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int kc_sss_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int kc_sss_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return kc_handle_sss(buffer, bytes); } @@ -347,7 +347,7 @@ static int kc_sss_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) ********************************************************************/ static int kc_sss_to_wav_size(const uint8_t *casdata, int caslen) { - kc_image_size = caslen ; + kc_image_size = caslen; return kc_handle_sss( nullptr, casdata ); } diff --git a/src/lib/formats/kim1_cas.cpp b/src/lib/formats/kim1_cas.cpp index 933e8cc3818..de2ee022632 100644 --- a/src/lib/formats/kim1_cas.cpp +++ b/src/lib/formats/kim1_cas.cpp @@ -145,7 +145,7 @@ static int kim1_handle_kim(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int kim1_kim_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int kim1_kim_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return kim1_handle_kim( buffer, bytes ); } diff --git a/src/lib/formats/lviv_lvt.cpp b/src/lib/formats/lviv_lvt.cpp index c2ffe37d9c9..e37508ab529 100644 --- a/src/lib/formats/lviv_lvt.cpp +++ b/src/lib/formats/lviv_lvt.cpp @@ -71,7 +71,7 @@ static int lviv_cassette_calculate_size_in_samples(const uint8_t *bytes, int len /*************************************************************************************/ -static int lviv_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int lviv_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { int16_t * p = buffer; diff --git a/src/lib/formats/lw30_dsk.cpp b/src/lib/formats/lw30_dsk.cpp index dd5eef5da5f..dd1536755d5 100644 --- a/src/lib/formats/lw30_dsk.cpp +++ b/src/lib/formats/lw30_dsk.cpp @@ -138,9 +138,11 @@ static constexpr int raw_track_size = 2/*0xaa*/ + 48/*0xaa*/ + SECTORS_PER_TRACK int lw30_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint64_t size = 0; - io.length(size); + if(io.length(size)) + return 0; + if(size == TRACKS_PER_DISK * SECTORS_PER_TRACK * SECTOR_SIZE) - return 50; // identified by size + return FIFID_SIZE; // identified by size return 0; } @@ -150,9 +152,8 @@ bool lw30_format::load(util::random_read &io, uint32_t form_factor, const std::v uint8_t trackdata[SECTORS_PER_TRACK * SECTOR_SIZE], rawdata[CELLS_PER_REV / 8]; memset(rawdata, 0xaa, sizeof(rawdata)); for(int track = 0; track < TRACKS_PER_DISK; track++) { - size_t actual{}; - io.read_at(track * SECTORS_PER_TRACK * SECTOR_SIZE, trackdata, SECTORS_PER_TRACK * SECTOR_SIZE, actual); - if(actual != SECTORS_PER_TRACK * SECTOR_SIZE) + auto const [err, actual] = read_at(io, track * SECTORS_PER_TRACK * SECTOR_SIZE, trackdata, SECTORS_PER_TRACK * SECTOR_SIZE); + if(err || (actual != SECTORS_PER_TRACK * SECTOR_SIZE)) return false; size_t i = 0; for(int x = 0; x < 2 + 48; x++) diff --git a/src/lib/formats/m20_dsk.cpp b/src/lib/formats/m20_dsk.cpp index 10c6cf51cf1..02905ecfa0d 100644 --- a/src/lib/formats/m20_dsk.cpp +++ b/src/lib/formats/m20_dsk.cpp @@ -62,8 +62,7 @@ bool m20_format::load(util::random_read &io, uint32_t form_factor, const std::ve bool mfm = track || head; desc_pc_sector sects[16]; uint8_t sectdata[16*256]; - size_t actual; - io.read_at(16*256*(track*2+head), sectdata, 16*256, actual); + /*auto const [err, actual] =*/ read_at(io, 16*256*(track*2+head), sectdata, 16*256); // FIXME: check for errors and premature EOF for (int i = 0; i < 16; i++) { int j = i/2 + (i & 1 ? 0 : 8); sects[i].track = track; @@ -92,17 +91,16 @@ bool m20_format::save(util::random_read_write &io, const std::vector<uint32_t> & int track_count, head_count; track_count = 35; head_count = 2; //FIXME: use image.get_actual_geometry(track_count, head_count) instead - // initial fm track + // initial FM track 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++) { - size_t actual; - io.write_at(file_offset, sectors[i + 1].data(), 128, actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, sectors[i + 1].data(), 128); // FIXME: check for errors file_offset += 256; //128; } - // rest are mfm tracks + // rest are MFM tracks for (int track = 0; track < track_count; track++) { for (int head = 0; head < head_count; head++) { // skip track 0, head 0 @@ -115,8 +113,7 @@ bool m20_format::save(util::random_read_write &io, const std::vector<uint32_t> & sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); for (int i = 0; i < 16; i++) { - size_t actual; - io.write_at(file_offset, sectors[i + 1].data(), 256, actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, sectors[i + 1].data(), 256); // FIXME: check for errors file_offset += 256; } } diff --git a/src/lib/formats/mbee_cas.cpp b/src/lib/formats/mbee_cas.cpp index cd11f7bb041..f8c42602b2b 100644 --- a/src/lib/formats/mbee_cas.cpp +++ b/src/lib/formats/mbee_cas.cpp @@ -209,7 +209,7 @@ static int mbee_handle_tap(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int mbee_tap_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int mbee_tap_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return mbee_handle_tap(buffer, bytes); } diff --git a/src/lib/formats/mdos_dsk.cpp b/src/lib/formats/mdos_dsk.cpp index 765ce1bc63c..a14df309db4 100644 --- a/src/lib/formats/mdos_dsk.cpp +++ b/src/lib/formats/mdos_dsk.cpp @@ -55,6 +55,8 @@ #include "ioprocs.h" #include "multibyte.h" +#include <tuple> + mdos_format::mdos_format() : wd177x_format(formats) { @@ -77,10 +79,10 @@ const char *mdos_format::extensions() const noexcept int mdos_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - int type = find_size(io, form_factor, variants); + int const type = find_size(io, form_factor, variants); if (type != -1) - return FIFID_SIZE; + return FIFID_SIZE | FIFID_STRUCT; return 0; } @@ -115,18 +117,22 @@ int mdos_format::parse_date_field(const uint8_t *str) int mdos_format::find_size(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { + std::error_condition err; size_t actual; + uint64_t size; if (io.length(size)) return -1; + // Look at the disk ID sector. disk_id_sector info; - // Look at the disk id sector. - io.read_at(0, &info, sizeof(struct disk_id_sector), actual); + std::tie(err, actual) = read_at(io, 0, &info, sizeof(disk_id_sector)); + if (err || (sizeof(disk_id_sector) != actual)) + return -1; 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); - // The 'unused' area is not necessarily zero filled and is ignoded + // The 'unused' area is not necessarily zero filled and is ignored // in the identification of a MDOS format image. // Expect an ASCII id, version, revision, and 'user name' strings. @@ -146,9 +152,9 @@ int mdos_format::find_size(util::random_read &io, uint32_t form_factor, const st return -1; // The date should be the numeric day, month and year. - int month = parse_date_field(info.date); - int day = parse_date_field(info.date + 2); - int year = parse_date_field(info.date + 4); + int const month = parse_date_field(info.date); + int const day = parse_date_field(info.date + 2); + int const year = parse_date_field(info.date + 4); LOG_FORMATS(" day %d, month %d, year %d\n", day, month, year); if (day < 1 || day > 32 || month < 1 || month > 12 || year < 0) @@ -182,8 +188,12 @@ int mdos_format::find_size(util::random_read &io, uint32_t form_factor, const st // the extent of the disk are free or available. uint8_t cluster_allocation[128], cluster_available[128]; - io.read_at(1 * 128, &cluster_allocation, sizeof(cluster_allocation), actual); - io.read_at(2 * 128, &cluster_available, sizeof(cluster_available), actual); + std::tie(err, actual) = read_at(io, 1 * 128, &cluster_allocation, sizeof(cluster_allocation)); + if (err || (sizeof(cluster_allocation) != actual)) + return -1; + std::tie(err, actual) = read_at(io, 2 * 128, &cluster_available, sizeof(cluster_available)); + if (err || (sizeof(cluster_available) != actual)) + return -1; for (int cluster = 0; cluster < sizeof(cluster_allocation) * 8; cluster++) { if (cluster * 4 * 128 + 4 * 128 > size) { @@ -202,7 +212,7 @@ int mdos_format::find_size(util::random_read &io, uint32_t form_factor, const st } } - for (int i=0; formats[i].form_factor; i++) { + for (int i = 0; formats[i].form_factor; i++) { const format &f = formats[i]; LOG_FORMATS(" checking format %d with form factor %02x, %d sectors, %d heads\n", i, f.form_factor, f.sector_count, f.head_count); diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index e6700f8f18f..eb1e632ec03 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -8,6 +8,7 @@ #include <cstring> #include <functional> +#include <tuple> /* @@ -41,8 +42,10 @@ - 2, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing - 3, MG_E -> End of zone - Tracks data is aligned so that the index pulse is at the start, - whether the disk is hard-sectored or not. + Tracks data is aligned so that the index pulse is at the start for soft- + sectored disks. For hard-sectored disks, the sector hole for the first + sector is at the start and the index hole is half a sector from the end + of the track. The position is the angular position in units of 1/200,000,000th of a turn. A size in such units, not coincidentally at all, is also @@ -58,7 +61,9 @@ if you try to rewrite a physical disk with the data. Some preservation formats encode that information, it is guessed for others. The write track function of fdcs should set it. The - representation is the angular position relative to the index. + representation is the angular position relative to the index, for + soft-sectored disks, and the first sector hole for hard-sectored + disks. The media type is divided in two parts. The first half indicate the physical form factor, i.e. all medias with that @@ -99,38 +104,46 @@ bool mfi_format::supports_save() const noexcept int mfi_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { header h; + auto const [err, actual] = read_at(io, 0, &h, sizeof(header)); + if (err || (sizeof(header) != actual)) + return 0; - size_t actual; - io.read_at(0, &h, sizeof(header), actual); - if((memcmp( h.sign, sign, 16) == 0 || memcmp( h.sign, sign_old, 16) == 0) && + if((!memcmp(h.sign, sign, 16) || !memcmp(h.sign, sign_old, 16)) && (h.cyl_count & CYLINDER_MASK) <= 84 && (h.cyl_count >> RESOLUTION_SHIFT) < 3 && h.head_count <= 2 && (!form_factor || !h.form_factor || h.form_factor == form_factor)) return FIFID_SIGN|FIFID_STRUCT; + return 0; } bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; + header h; - entry entries[84*2*4]; - io.read_at(0, &h, sizeof(header), actual); - int resolution = h.cyl_count >> RESOLUTION_SHIFT; + std::tie(err, actual) = read_at(io, 0, &h, sizeof(header)); + if(err || (sizeof(header) != actual)) + return false; + int const resolution = h.cyl_count >> RESOLUTION_SHIFT; h.cyl_count &= CYLINDER_MASK; - 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); if(!h.cyl_count) return true; + entry entries[84*2*4]; + std::tie(err, actual) = read_at(io, sizeof(header), &entries, (h.cyl_count << resolution)*h.head_count*sizeof(entry)); + if(err || (((h.cyl_count << resolution)*h.head_count*sizeof(entry)) != actual)) + return false; + std::function<void (const std::vector<uint32_t> &src, std::vector<uint32_t> &track)> converter; - if(!memcmp( h.sign, sign, 16)) { - converter = [](const std::vector<uint32_t> &src, std::vector<uint32_t> &track) -> void { + if(!memcmp(h.sign, sign, 16)) { + converter = [] (const std::vector<uint32_t> &src, std::vector<uint32_t> &track) { uint32_t ctime = 0; for(uint32_t mg : src) { ctime += mg & TIME_MASK; @@ -139,7 +152,7 @@ bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve }; } else { - converter = [](const std::vector<uint32_t> &src, std::vector<uint32_t> &track) -> void { + converter = [] (const std::vector<uint32_t> &src, std::vector<uint32_t> &track) { unsigned int cell_count = src.size(); uint32_t mg = src[0] & MG_MASK; uint32_t wmg = src[cell_count - 1] & MG_MASK; @@ -184,7 +197,7 @@ bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve compressed.resize(ent->compressed_size); uncompressed.resize(cell_count); - io.read_at(ent->offset, &compressed[0], ent->compressed_size, actual); + std::tie(err, actual) = read_at(io, ent->offset, &compressed[0], ent->compressed_size); // FIXME: check for errors and premature EOF uLongf size = ent->uncompressed_size; if(uncompress((Bytef *)uncompressed.data(), &size, &compressed[0], ent->compressed_size) != Z_OK) { @@ -204,7 +217,6 @@ bool mfi_format::load(util::random_read &io, uint32_t form_factor, const std::ve bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - size_t actual; int tracks, heads; image.get_actual_geometry(tracks, heads); int resolution = image.get_resolution(); @@ -224,7 +236,7 @@ bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> & h.form_factor = image.get_form_factor(); h.variant = image.get_variant(); - io.write_at(0, &h, sizeof(header), actual); + write_at(io, 0, &h, sizeof(header)); // FIXME: check for errors memset(entries, 0, sizeof(entries)); @@ -258,11 +270,11 @@ bool mfi_format::save(util::random_read_write &io, const std::vector<uint32_t> & entries[epos].write_splice = image.get_write_splice_position(track >> 2, head, track & 3); epos++; - io.write_at(pos, postcomp.get(), csize, actual); + write_at(io, pos, postcomp.get(), csize); // FIXME: check for errors pos += csize; } - io.write_at(sizeof(header), entries, (tracks << resolution)*heads*sizeof(entry), actual); + write_at(io, sizeof(header), entries, (tracks << resolution)*heads*sizeof(entry)); // FIXME: check for errors return true; } diff --git a/src/lib/formats/mfi_dsk.h b/src/lib/formats/mfi_dsk.h index 89201c6db8a..7241bcfab32 100644 --- a/src/lib/formats/mfi_dsk.h +++ b/src/lib/formats/mfi_dsk.h @@ -45,13 +45,13 @@ private: static const char sign[16]; struct header { - char sign[16]; - unsigned int cyl_count, head_count; - unsigned int form_factor, variant; + uint8_t sign[16]; + uint32_t cyl_count, head_count; + uint32_t form_factor, variant; }; struct entry { - unsigned int offset, compressed_size, uncompressed_size, write_splice; + uint32_t offset, compressed_size, uncompressed_size, write_splice; }; }; diff --git a/src/lib/formats/mz_cas.cpp b/src/lib/formats/mz_cas.cpp index 6bc82a43bd1..ddc35b62663 100644 --- a/src/lib/formats/mz_cas.cpp +++ b/src/lib/formats/mz_cas.cpp @@ -69,7 +69,7 @@ static int fill_wave_b(int16_t *buffer, int offs, int byte) return count; } -static int fill_wave(int16_t *buffer, int length, uint8_t *code) +static int fill_wave(int16_t *buffer, int length, const uint8_t *code, int) { static int16_t *beg; static uint16_t csum = 0; diff --git a/src/lib/formats/nabupc_dsk.cpp b/src/lib/formats/nabupc_dsk.cpp index 79d67a5e25f..00205c1e560 100644 --- a/src/lib/formats/nabupc_dsk.cpp +++ b/src/lib/formats/nabupc_dsk.cpp @@ -18,6 +18,7 @@ #include "ioprocs.h" #include "strformat.h" + const nabupc_format::format nabupc_format::formats[] = { { // 200k 40 track single sided double density (nabu) @@ -167,8 +168,7 @@ bool nabupc_format::load(util::random_read &io, uint32_t form_factor, const std: for (int head = 0; head < f.head_count; head++) { desc_pc_sector sects[sector_count]; uint8_t sectdata[sector_count * sector_size]; - size_t actual; - io.read_at((track * f.head_count + head) * sector_count * sector_size, sectdata, sector_count * sector_size, actual); + /*auto const [err, actual] =*/ read_at(io, (track * f.head_count + head) * sector_count * sector_size, sectdata, sector_count * sector_size); // FIXME: check for errors and premature EOF for (int i = 0; i < sector_count; i++) { sects[i].track = track; sects[i].head = head; @@ -196,8 +196,7 @@ bool nabupc_format::save(util::random_read_write &io, const std::vector<uint32_t auto bitstream = generate_bitstream_from_track(track, head, 2000, image); auto sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); for (int i = 0; i < sector_count; i++) { - size_t actual; - io.write_at(file_offset, sectors[i + 1].data(), sector_size, actual); + /*auto const [err, actual] =*/ write_at(io, file_offset, sectors[i + 1].data(), sector_size); // FIXME: check for errors file_offset += sector_size; } } diff --git a/src/lib/formats/nfd_dsk.cpp b/src/lib/formats/nfd_dsk.cpp index 773b35d8aef..a51b461e144 100644 --- a/src/lib/formats/nfd_dsk.cpp +++ b/src/lib/formats/nfd_dsk.cpp @@ -108,10 +108,11 @@ const char *nfd_format::extensions() const noexcept int nfd_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[16]; - size_t actual; - io.read_at(0, h, 16, actual); + auto const [err, actual] = read_at(io, 0, h, 16); // TODO: does it really need 16 bytes? it only looks at 14. + if (err || (16 != actual)) + return 0; - if (strncmp((const char *)h, "T98FDDIMAGE.R0", 14) == 0 || strncmp((const char *)h, "T98FDDIMAGE.R1", 14) == 0) + if (!memcmp(h, "T98FDDIMAGE.R0", 14) || !memcmp(h, "T98FDDIMAGE.R1", 14)) return FIFID_SIGN; return 0; @@ -119,13 +120,12 @@ int nfd_format::identify(util::random_read &io, uint32_t form_factor, const std: bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; uint64_t size; if (io.length(size)) return false; uint8_t h[0x120], hsec[0x10]; - io.read_at(0, h, 0x120, actual); - int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; + read_at(io, 0, h, 0x120); // FIXME: check for errors and premature EOF + int format_version = !memcmp(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) uint8_t disk_type = 0; @@ -149,7 +149,7 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve { int curr_track_size = 0; // read sector map absolute location - io.read_at(pos, hsec, 4, actual); + read_at(io, pos, hsec, 4); // FIXME: check for errors and premature EOF pos += 4; uint32_t secmap_addr = little_endianize_int32(*(uint32_t *)(hsec)); @@ -158,14 +158,14 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve // 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.read_at(secmap_addr, hsec, 0x10, actual); + read_at(io, secmap_addr, hsec, 0x10); // FIXME: check for errors and premature EOF 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.read_at(secmap_addr, hsec, 0x10, actual); + read_at(io, secmap_addr, hsec, 0x10); // FIXME: check for errors and premature EOF if (track == 0 && sect == 0) disk_type = hsec[0xb]; // can this change across the disk? I don't think so... @@ -184,7 +184,7 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve { for (int sect = 0; sect < num_specials[track]; sect++) { - io.read_at(secmap_addr, hsec, 0x10, actual); + read_at(io, secmap_addr, hsec, 0x10); // FIXME: check for errors and premature EOF secmap_addr += 0x10; curr_track_size += (hsec[9] + 1) * little_endianize_int32(*(uint32_t *)(hsec + 0x0a)); } @@ -207,7 +207,7 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve { // read sector map for this sector // for rev.0 format each sector uses 0x10 bytes - io.read_at(pos, hsec, 0x10, actual); + read_at(io, pos, hsec, 0x10); // FIXME: check for errors and premature EOF if (track == 0 && sect == 0) disk_type = hsec[0xa]; // can this change across the disk? I don't think so... @@ -254,7 +254,7 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve for (int track = 0; track < 163 && pos < size; track++) { - io.read_at(pos, sect_data, track_sizes[track], actual); + read_at(io, pos, sect_data, track_sizes[track]); // FIXME: check for errors and premature EOF for (int i = 0; i < num_secs[track]; i++) { @@ -277,7 +277,7 @@ bool nfd_format::load(util::random_read &io, uint32_t form_factor, const std::ve if (mfm[track * 26]) build_pc_track_mfm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); else - build_pc_track_fm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); + build_pc_track_fm(track / 2, track % 2, image, cell_count / 2, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); } return true; diff --git a/src/lib/formats/orao_cas.cpp b/src/lib/formats/orao_cas.cpp index a580fdef077..8cc77e3bf6f 100644 --- a/src/lib/formats/orao_cas.cpp +++ b/src/lib/formats/orao_cas.cpp @@ -62,7 +62,7 @@ static int orao_cas_to_wav_size( const uint8_t *casdata, int caslen ) { return size; } -static int orao_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int orao_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i,j,size,k; uint8_t b; size = 0; diff --git a/src/lib/formats/oric_dsk.cpp b/src/lib/formats/oric_dsk.cpp index f4d9b78faa9..15bb5ce1455 100644 --- a/src/lib/formats/oric_dsk.cpp +++ b/src/lib/formats/oric_dsk.cpp @@ -12,6 +12,7 @@ #include "ioprocs.h" #include "multibyte.h" +#include "osdcore.h" #include <cstring> @@ -39,8 +40,7 @@ bool oric_dsk_format::supports_save() const noexcept int oric_dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[256]; - size_t actual; - io.read_at(0, h, 256, actual); + /*auto const [err, actual] =*/ read_at(io, 0, h, 256); // FIXME: check for errors and premature EOF if(memcmp(h, "MFM_DISK", 8)) return 0; @@ -60,19 +60,29 @@ int oric_dsk_format::identify(util::random_read &io, uint32_t form_factor, const bool oric_dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; uint8_t h[256]; uint8_t t[6250+3]; t[6250] = t[6251] = t[6252] = 0; - io.read_at(0, h, 256, actual); + read_at(io, 0, h, 256); // FIXME: check for errors and premature EOF int sides = get_u32le(&h[ 8]); int tracks = get_u32le(&h[12]); + int max_tracks, max_sides; + image.get_maximal_geometry(max_tracks, max_sides); + if (tracks > max_tracks) { + osd_printf_error("oric_dsk: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", tracks, max_tracks); + return false; + } + if (sides > max_sides) { + osd_printf_warning("oric_dsk: Floppy disk has excess of heads for this drive that will be discarded (floppy heads=%d, drive heads=%d).\n", sides, max_sides); + sides = max_sides; + } + for(int side=0; side<sides; side++) for(int track=0; track<tracks; track++) { - io.read_at(256+6400*(tracks*side + track), t, 6250, actual); + read_at(io, 256+6400*(tracks*side + track), t, 6250); // FIXME: check for errors and premature EOF std::vector<uint32_t> stream; int sector_size = 128; for(int i=0; i<6250; i++) { @@ -157,9 +167,9 @@ bool oric_jasmin_format::load(util::random_read &io, uint32_t form_factor, const int const heads = size == 41*17*256 ? 1 : 2; - std::vector<uint8_t> data(size); - size_t actual; - io.read_at(0, data.data(), size, actual); + auto const [err, data, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return false; for(int head = 0; head != heads; head++) for(int track = 0; track != 41; track++) { @@ -171,7 +181,7 @@ bool oric_jasmin_format::load(util::random_read &io, uint32_t form_factor, const sdesc[s].sector = sector + 1; sdesc[s].size = 1; sdesc[s].actual_size = 256; - sdesc[s].data = data.data() + 256 * (sector + track*17 + head*17*41); + sdesc[s].data = &data[256 * (sector + track*17 + head*17*41)]; sdesc[s].deleted = false; sdesc[s].bad_crc = false; } @@ -203,8 +213,7 @@ bool oric_jasmin_format::save(util::random_read_write &io, const std::vector<uin auto sectors = extract_sectors_from_bitstream_mfm_pc(generate_bitstream_from_track(track, head, 2000, image)); for(unsigned int sector = 0; sector != 17; sector ++) { 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); + /*auto const [err, actual] =*/ write_at(io, 256 * (sector + track*17 + head*17*41), data, 256); // FIXME: check for errors } } return true; diff --git a/src/lib/formats/oric_tap.cpp b/src/lib/formats/oric_tap.cpp index 7f900808f21..a8b11a5ee7a 100644 --- a/src/lib/formats/oric_tap.cpp +++ b/src/lib/formats/oric_tap.cpp @@ -345,139 +345,135 @@ static int oric_cassette_calculate_size_in_samples(const uint8_t *bytes, int len } /* length is length of sample buffer to fill! */ -static int oric_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int oric_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { unsigned char header[9]; - uint8_t *data_ptr; - int16_t *p; - int i; - uint8_t data; - - p = buffer; - + int16_t *p = buffer; /* header and trailer act as pauses */ /* the trailer is required so that the via sees the last bit of the last byte */ - if (bytes == CODE_HEADER) { - for (i = 0; i < ORIC_WAVESAMPLES_HEADER; i++) + if (bytes == CODE_HEADER) + { + for (int i = 0; i < ORIC_WAVESAMPLES_HEADER; i++) *(p++) = WAVEENTRY_NULL; } - else if (bytes == CODE_TRAILER) { - for (i = 0; i < ORIC_WAVESAMPLES_TRAILER; i++) + else if (bytes == CODE_TRAILER) + { + for (int i = 0; i < ORIC_WAVESAMPLES_TRAILER; i++) *(p++) = WAVEENTRY_NULL; } else -{ - /* the length is the number of samples left in the buffer and NOT the number of bytes for the input file */ - length = length - ORIC_WAVESAMPLES_TRAILER; - - oric.cassette_state = ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE; - data_ptr = bytes; - - while ((data_ptr<(bytes + oric.tap_size)) && (p < (buffer+length)) ) { - data = data_ptr[0]; - data_ptr++; + /* the length is the number of samples left in the buffer and NOT the number of bytes for the input file */ + length = length - ORIC_WAVESAMPLES_TRAILER; - switch (oric.cassette_state) + oric.cassette_state = ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE; + const uint8_t *data_ptr = bytes; + + while ((data_ptr < (bytes + oric.tap_size)) && (p < (buffer+length)) ) { - case ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE: - { - if (data==ORIC_SYNC_BYTE) - { - LOG_FORMATS("found sync byte!\n"); - /* found first sync byte */ - oric.cassette_state = ORIC_CASSETTE_GOT_SYNC_BYTE; - } - } - break; + const uint8_t data = data_ptr[0]; + data_ptr++; - case ORIC_CASSETTE_GOT_SYNC_BYTE: + switch (oric.cassette_state) { - if (data!=ORIC_SYNC_BYTE) + case ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE: { - /* 0.25 second pause */ - p = oric_fill_pause(p, oric_seconds_to_samples(0.25)); - - LOG_FORMATS("found end of sync bytes!\n"); - /* found end of sync bytes */ - for (i=0; i<ORIC_LEADER_LENGTH; i++) + if (data == ORIC_SYNC_BYTE) { - p = oric_output_byte(p,0x016); + LOG_FORMATS("found sync byte!\n"); + /* found first sync byte */ + oric.cassette_state = ORIC_CASSETTE_GOT_SYNC_BYTE; } + } + break; - if (data==0x024) + case ORIC_CASSETTE_GOT_SYNC_BYTE: + { + if (data != ORIC_SYNC_BYTE) { - //LOG_FORMATS("reading header!\n"); - p = oric_output_byte(p,data); - oric.cassette_state = ORIC_CASSETTE_READ_HEADER; - oric.data_count = 0; - oric.data_length = 9; + /* 0.25 second pause */ + p = oric_fill_pause(p, oric_seconds_to_samples(0.25)); + + LOG_FORMATS("found end of sync bytes!\n"); + /* found end of sync bytes */ + for (int i = 0; i < ORIC_LEADER_LENGTH; i++) + { + p = oric_output_byte(p,0x016); + } + + if (data == 0x024) + { + //LOG_FORMATS("reading header!\n"); + p = oric_output_byte(p, data); + oric.cassette_state = ORIC_CASSETTE_READ_HEADER; + oric.data_count = 0; + oric.data_length = 9; + } } } - } - break; - - case ORIC_CASSETTE_READ_HEADER: - { - header[oric.data_count] = data; - p = oric_output_byte(p, data); - oric.data_count++; + break; - if (oric.data_count==oric.data_length) + case ORIC_CASSETTE_READ_HEADER: { - //LOG_FORMATS("finished reading header!\n"); - oric.cassette_state = ORIC_CASSETTE_READ_FILENAME; - } - } - break; + header[oric.data_count] = data; + p = oric_output_byte(p, data); + oric.data_count++; - case ORIC_CASSETTE_READ_FILENAME: - { - p = oric_output_byte(p, data); + if (oric.data_count==oric.data_length) + { + //LOG_FORMATS("finished reading header!\n"); + oric.cassette_state = ORIC_CASSETTE_READ_FILENAME; + } + } + break; - /* got end of filename? */ - if (data==0) + case ORIC_CASSETTE_READ_FILENAME: { - uint16_t end, start; - LOG_FORMATS("got end of filename\n"); + p = oric_output_byte(p, data); - /* oric includes a small delay, but I don't see - it being 1 bits */ - for (i=0; i<100; i++) + /* got end of filename? */ + if (data == 0) { - p = oric_output_bit(p,1); - } + uint16_t end, start; + LOG_FORMATS("got end of filename\n"); - oric.cassette_state = ORIC_CASSETTE_WRITE_DATA; - oric.data_count = 0; + /* oric includes a small delay, but I don't see + it being 1 bits */ + for (int i = 0; i < 100; i++) + { + p = oric_output_bit(p,1); + } - end = get_u16be(&header[4]); - start = get_u16be(&header[6]); - LOG(("start (from header): %02x\n",start)); - LOG(("end (from header): %02x\n",end)); - oric.data_length = end - start + 1; - } - } - break; + oric.cassette_state = ORIC_CASSETTE_WRITE_DATA; + oric.data_count = 0; - case ORIC_CASSETTE_WRITE_DATA: - { - p = oric_output_byte(p, data); - oric.data_count++; + end = get_u16be(&header[4]); + start = get_u16be(&header[6]); + LOG(("start (from header): %02x\n",start)); + LOG(("end (from header): %02x\n",end)); + oric.data_length = end - start + 1; + } + } + break; - if (oric.data_count==oric.data_length) + case ORIC_CASSETTE_WRITE_DATA: { - LOG_FORMATS("finished writing data!\n"); - oric.cassette_state = ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE; + p = oric_output_byte(p, data); + oric.data_count++; + + if (oric.data_count==oric.data_length) + { + LOG_FORMATS("finished writing data!\n"); + oric.cassette_state = ORIC_CASSETTE_SEARCHING_FOR_SYNC_BYTE; + } } - } - break; + break; + } } } -} return p - buffer; } diff --git a/src/lib/formats/os9_dsk.cpp b/src/lib/formats/os9_dsk.cpp index f74cd7fb3a6..ca79ced2145 100644 --- a/src/lib/formats/os9_dsk.cpp +++ b/src/lib/formats/os9_dsk.cpp @@ -88,8 +88,7 @@ int os9_format::find_size(util::random_read &io, uint32_t form_factor, const std return -1; uint8_t os9_header[0x60]; - size_t actual; - io.read_at(0, os9_header, sizeof(os9_header), actual); + /*auto const [err, actual] =*/ read_at(io, 0, os9_header, sizeof(os9_header)); // FIXME: check for errors and premature EOF int os9_total_sectors = get_u24be(&os9_header[0x00]); int os9_heads = util::BIT(os9_header[0x10], 0) ? 2 : 1; diff --git a/src/lib/formats/p6001_cas.cpp b/src/lib/formats/p6001_cas.cpp index c4689eb9be4..cdb0b922680 100644 --- a/src/lib/formats/p6001_cas.cpp +++ b/src/lib/formats/p6001_cas.cpp @@ -53,7 +53,7 @@ static int pc6001_cas_to_wav_size (const uint8_t *casdata, int caslen) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int pc6001_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int pc6001_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return pc6001_handle_cas(buffer,bytes); } diff --git a/src/lib/formats/pasti_dsk.cpp b/src/lib/formats/pasti_dsk.cpp index 1390072b97c..ae82ee7939b 100644 --- a/src/lib/formats/pasti_dsk.cpp +++ b/src/lib/formats/pasti_dsk.cpp @@ -45,11 +45,10 @@ bool pasti_format::supports_save() const noexcept int pasti_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { uint8_t h[16]; - size_t actual; - io.read_at(0, h, 16, actual); + /*auto const [err, actual] =*/ read_at(io, 0, h, 16); // FIXME: check for errors and premature EOF if(!memcmp(h, "RSY\0\3\0", 6) && - (1 || (h[10] >= 80 && h[10] <= 82) || (h[10] >= 160 && h[10] <= 164))) + (1 || (h[10] >= 80 && h[10] <= 82) || (h[10] >= 160 && h[10] <= 164))) // TODO: why is this check disabled? return FIFID_SIGN; return 0; @@ -67,9 +66,8 @@ static void hexdump(const uint8_t *d, int s) bool pasti_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; uint8_t fh[16]; - io.read_at(0, fh, 16, actual); + read_at(io, 0, fh, 16); // FIXME: check for errors and premature EOF std::vector<uint8_t> raw_track; @@ -84,7 +82,7 @@ bool pasti_format::load(util::random_read &io, uint32_t form_factor, const std:: for(int track=0; track < tracks; track++) { for(int head=0; head < heads; head++) { uint8_t th[16]; - io.read_at(pos, th, 16, actual); + read_at(io, pos, th, 16); // FIXME: check for errors and premature EOF int entry_len = get_u32le(&th[0]); int fuzz_len = get_u32le(&th[4]); int sect = get_u16le(&th[8]); @@ -95,7 +93,7 @@ bool pasti_format::load(util::random_read &io, uint32_t form_factor, const std:: raw_track.resize(entry_len-16); - io.read_at(pos+16, &raw_track[0], entry_len-16, actual); + read_at(io, pos+16, &raw_track[0], entry_len-16); // FIXME: check for errors and premature EOF 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/pc98_dsk.cpp b/src/lib/formats/pc98_dsk.cpp index 534a5216450..36dac83e2af 100644 --- a/src/lib/formats/pc98_dsk.cpp +++ b/src/lib/formats/pc98_dsk.cpp @@ -83,6 +83,10 @@ const pc98_format::format pc98_format::formats[] = { floppy_image::FF_525, floppy_image::DSHD, floppy_image::MFM, 1200, 8, 77, 2, 1024, {}, 1, {}, 80, 50, 22, 84 }, + { /* 1MB 5 1/4 inch 256bps n88 basic disk type */ + floppy_image::FF_525, floppy_image::DSHD, floppy_image::MFM, + 1200, 26, 77, 2, 256, {}, 1, {}, 80, 50, 21, 77 + }, {} }; diff --git a/src/lib/formats/pc98fdi_dsk.cpp b/src/lib/formats/pc98fdi_dsk.cpp index b331ad8b521..10822ab316d 100644 --- a/src/lib/formats/pc98fdi_dsk.cpp +++ b/src/lib/formats/pc98fdi_dsk.cpp @@ -11,8 +11,9 @@ #include "pc98fdi_dsk.h" #include "ioprocs.h" +#include "multibyte.h" -#include "osdcomm.h" // little_endianize_int32 +#include <tuple> pc98fdi_format::pc98fdi_format() @@ -41,15 +42,16 @@ int pc98fdi_format::identify(util::random_read &io, uint32_t form_factor, const return 0; 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)); + auto const [err, actual] = read_at(io, 0, h, 32); + if(err || (32 != actual)) + return 0; + + uint32_t const hsize = get_u32le(h + 0x8); + uint32_t const psize = get_u32le(h + 0xc); + uint32_t const ssize = get_u32le(h + 0x10); + uint32_t const scnt = get_u32le(h + 0x14); + uint32_t const sides = get_u32le(h + 0x18); + uint32_t const ntrk = get_u32le(h + 0x1c); if(size == hsize + psize && psize == ssize*scnt*sides*ntrk) return FIFID_STRUCT; @@ -58,16 +60,19 @@ int pc98fdi_format::identify(util::random_read &io, uint32_t form_factor, const bool pc98fdi_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; uint8_t h[32]; - io.read_at(0, h, 32, actual); + std::tie(err, actual) = read_at(io, 0, h, 32); + if(err || (32 != actual)) + return false; - 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)); + uint32_t const hsize = get_u32le(h + 0x8); + uint32_t const sector_size = get_u32le(h + 0x10); + uint32_t const sector_count = get_u32le(h + 0x14); + uint32_t const head_count = get_u32le(h + 0x18); + uint32_t const track_count = get_u32le(h + 0x1c); int const cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; @@ -78,9 +83,9 @@ bool pc98fdi_format::load(util::random_read &io, uint32_t form_factor, const std desc_pc_sector sects[256]; uint8_t sect_data[65536]; - for(int track=0; track < track_count; track++) + for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { - io.read_at(hsize + sector_size*sector_count*(track*head_count + head), sect_data, sector_size*sector_count, actual); + std::tie(err, actual) = read_at(io, hsize + sector_size*sector_count*(track*head_count + head), sect_data, sector_size*sector_count); // FIXME: check for errors and premature EOF for(int i=0; i<sector_count; i++) { sects[i].track = track; @@ -95,6 +100,7 @@ bool pc98fdi_format::load(util::random_read &io, uint32_t form_factor, const std build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sector_size)); } + } return true; } diff --git a/src/lib/formats/phc25_cas.cpp b/src/lib/formats/phc25_cas.cpp index 8294df07628..e6dab7e88e1 100644 --- a/src/lib/formats/phc25_cas.cpp +++ b/src/lib/formats/phc25_cas.cpp @@ -129,7 +129,7 @@ static int phc25_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int phc25_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int phc25_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return phc25_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/pmd_cas.cpp b/src/lib/formats/pmd_cas.cpp index ef4cef7c00a..224a3b0af5b 100644 --- a/src/lib/formats/pmd_cas.cpp +++ b/src/lib/formats/pmd_cas.cpp @@ -168,7 +168,7 @@ static int pmd85_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int pmd85_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int pmd85_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return pmd85_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/poly_dsk.cpp b/src/lib/formats/poly_dsk.cpp index 4a264e293a1..8b8f48780f8 100644 --- a/src/lib/formats/poly_dsk.cpp +++ b/src/lib/formats/poly_dsk.cpp @@ -50,9 +50,8 @@ int poly_cpm_format::identify(util::random_read &io, uint32_t form_factor, const { // check for Poly CP/M boot sector 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) + auto const [err, actual] = read_at(io, 0, boot, 16); + if (!err && (16 == actual) && !memcmp(boot, "\x86\xc3\xb7\x00\x00\x8e\x10\xc0\xbf\x00\x01\xbf\xe0\x60\x00\x00", 16)) { return FIFID_SIZE|FIFID_SIGN; } @@ -114,8 +113,7 @@ bool poly_cpm_format::load(util::random_read &io, uint32_t form_factor, const st sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = §_data[sdatapos]; - size_t actual; - io.read(sects[i].data, bps, actual); + /*auto const [err, actual] =*/ read(io, sects[i].data, bps); // FIXME: check for errors and premature EOF sdatapos += bps; } // gap sizes unverified diff --git a/src/lib/formats/primoptp.cpp b/src/lib/formats/primoptp.cpp index ccadcb6d70d..81eaf65b65a 100644 --- a/src/lib/formats/primoptp.cpp +++ b/src/lib/formats/primoptp.cpp @@ -138,12 +138,12 @@ static int primo_cassette_calculate_size_in_samples(const uint8_t *bytes, int le return size_in_samples; } -static int primo_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int primo_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { int i = 0, j = 0, k; int16_t *p = buffer; - uint8_t *b = bytes; + const uint8_t *b = bytes; uint32_t file_size = 0; uint16_t block_size = 0; diff --git a/src/lib/formats/rk_cas.cpp b/src/lib/formats/rk_cas.cpp index 4747ccd50ed..25bbb79eea3 100644 --- a/src/lib/formats/rk_cas.cpp +++ b/src/lib/formats/rk_cas.cpp @@ -77,7 +77,7 @@ static int gam_cas_to_wav_size( const uint8_t *casdata, int caslen ) { return (RK_HEADER_LEN * 8 * 2 + caslen * 8 * 2) * RK_SIZE_20; } -static int rk20_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int rk20_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i; int16_t * p = buffer; @@ -93,7 +93,7 @@ static int rk20_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { return p - buffer; } -static int rk22_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int rk22_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i; int16_t * p = buffer; @@ -109,7 +109,7 @@ static int rk22_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { return p - buffer; } -static int rk60_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int rk60_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i; int16_t * p = buffer; @@ -125,7 +125,7 @@ static int rk60_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { return p - buffer; } -static int gam_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) { +static int gam_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int i; int16_t * p = buffer; diff --git a/src/lib/formats/rx50_dsk.cpp b/src/lib/formats/rx50_dsk.cpp index cefc2725209..853caf0dbc1 100644 --- a/src/lib/formats/rx50_dsk.cpp +++ b/src/lib/formats/rx50_dsk.cpp @@ -139,7 +139,7 @@ int rx50img_format::identify(util::random_read &io, uint32_t form_factor, const return 0; } - // /* Sectors are numbered 1 to 10 */ +// Sectors are numbered 1 to 10 bool rx50img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { uint8_t track_count, head_count, sector_count; @@ -158,8 +158,7 @@ bool rx50img_format::load(util::random_read &io, uint32_t form_factor, const std int track_size = sector_count*512; 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); + /*auto const [err, actual] =*/ read_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(rx50_10_desc, track, head, sectors, sector_count, 102064, image); // 98480 } } @@ -205,8 +204,7 @@ bool rx50img_format::save(util::random_read_write &io, const std::vector<uint32_ 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); - size_t actual; - io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors } } return true; diff --git a/src/lib/formats/sap_dsk.cpp b/src/lib/formats/sap_dsk.cpp new file mode 100644 index 00000000000..ef51cb8b772 --- /dev/null +++ b/src/lib/formats/sap_dsk.cpp @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#include "sap_dsk.h" + +#include "ioprocs.h" +#include "multibyte.h" + +static constexpr unsigned HEADER_LENGTH = 66; +static constexpr uint8_t MAGIC_XOR = 0xb3; + +const sap_dsk_format FLOPPY_SAP_FORMAT; + +inline uint16_t sap_dsk_format::accumulate_crc(uint16_t crc, uint8_t data) noexcept +{ + // Almost CRC16-CCITT, but not quite... + for (int shift : {0, 4}) + crc = ((crc >> 4) & 0xfff) ^ 0x1081 * ((crc ^ (data >> shift)) & 0xf); + return crc; +} + +const char *sap_dsk_format::name() const noexcept +{ + return "sap"; +} + +const char *sap_dsk_format::description() const noexcept +{ + return "Thomson SAP disk image (Systeme d'Archivage Pukall)"; +} + +const char *sap_dsk_format::extensions() const noexcept +{ + return "sap"; +} + +bool sap_dsk_format::supports_save() const noexcept +{ + return false; +} + +int sap_dsk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const +{ + uint8_t buffer[HEADER_LENGTH]; + auto [err, actual] = read_at(io, 0, buffer, HEADER_LENGTH); + if (err || actual != HEADER_LENGTH) + return 0; + + // Check ID string + if (memcmp(&buffer[1], "SYSTEME D'ARCHIVAGE PUKALL S.A.P. (c) Alexandre PUKALL Avril 1998", HEADER_LENGTH - 1) != 0) + return 0; + + // Check disk format + if (form_factor == floppy_image::FF_35) + { + // 3.5" disks must have 80 double-density tracks + if ((buffer[0] & 0x7f) != 0x01) + return 0; + } + else if (form_factor == floppy_image::FF_525) + { + // 5.25" disks must have 40 tracks + if ((buffer[0] & 0x7e) != 0x02) + return 0; + } + else if (form_factor != floppy_image::FF_UNKNOWN) + return 0; + + uint32_t expected_size = HEADER_LENGTH + uint32_t((buffer[0] & 0x01) ? 256 + 6 : 128 + 6) * ((buffer[0] & 0x02) ? 40 : 80) * 16 * ((buffer[0] & 0x80) ? 2 : 1); + uint64_t actual_size; + if (!io.length(actual_size) && expected_size == actual_size) + return FIFID_SIGN | FIFID_SIZE; + else + return FIFID_SIGN; +} + +bool sap_dsk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const +{ + uint8_t disk_type; + if (auto [err, actual] = read_at(io, 0, &disk_type, 1); err || actual != 1) + return false; + + int track_count = (disk_type & 0x02) ? 40 : 80; + int head_count = (disk_type & 0x80) ? 2 : 1; + int max_tracks, max_heads; + image.get_maximal_geometry(max_tracks, max_heads); + if (max_heads < head_count || max_tracks < track_count) + return false; + + switch (disk_type & 0x03) + { + case 0x01: + image.set_form_variant(floppy_image::FF_35, (disk_type & 0x80) ? floppy_image::DSDD : floppy_image::SSDD); + break; + + case 0x02: + image.set_form_variant(floppy_image::FF_525, (disk_type & 0x80) ? floppy_image::DSSD : floppy_image::SSSD); + break; + + case 0x03: + image.set_form_variant(floppy_image::FF_525, (disk_type & 0x80) ? floppy_image::DSDD : floppy_image::SSDD); + break; + + default: + return false; + } + + uint8_t sector_buf[16 * 1024]; + uint8_t sector_header[4]; + uint8_t sector_crc[2]; + desc_pc_sector sectors[16]; + + size_t read_offset = HEADER_LENGTH; + for (int head = 0; head < head_count; head++) + { + for (int track = 0; track < track_count; track++) + { + uint8_t *bufptr = §or_buf[0]; + uint8_t track_size = 16; + int sector_count = 0; + bool is_mfm = disk_type & 0x01; + while (track_size != 0) + { + if (auto [err, actual] = read_at(io, read_offset, §or_header[0], 4); err || actual != 4) + return false; + if (sector_count == 0 && sector_header[0] == 0x01) + is_mfm = false; + uint8_t sector_size = (sector_header[0] & 0x02) ? 4 >> (sector_header[0] & 0x01) : 1; + if (track_size < sector_size) + return false; + uint16_t sector_octets = sector_size * (is_mfm ? 256 : 128); + if (auto [err, actual] = read_at(io, read_offset + 4, bufptr, sector_octets); err || actual != sector_octets) + return false; + if (auto [err, actual] = read_at(io, read_offset + 4 + sector_octets, §or_crc[0], 2); err || actual != 2) + return false; + + uint16_t crc = 0xffff; + for (uint8_t data : sector_header) + crc = accumulate_crc(crc, data); + for (uint16_t i = 0; i < sector_octets; i++) + { + bufptr[i] ^= MAGIC_XOR; + crc = accumulate_crc(crc, bufptr[i]); + } + + sectors[sector_count].track = sector_header[2]; + sectors[sector_count].head = head; + sectors[sector_count].sector = sector_header[3]; + sectors[sector_count].size = sector_size; + sectors[sector_count].actual_size = sector_octets; + sectors[sector_count].data = bufptr; + // Teo claims this flag is set for protection with "all the gap bytes set to 0xF7"; actual purpose is a bit unclear + sectors[sector_count].deleted = bool(sector_header[0] & 0x04); + sectors[sector_count].bad_crc = crc != get_u16be(sector_crc); + + read_offset += sector_octets + 6; + bufptr += sector_octets; + track_size -= sector_size; + sector_count++; + } + if (is_mfm) + build_pc_track_mfm(track, head, image, 100000, sector_count, sectors, calc_default_pc_gap3_size(form_factor, sectors[0].actual_size)); + else + build_pc_track_fm(track, head, image, 100000 / 2, sector_count, sectors, calc_default_pc_gap3_size(form_factor, sectors[0].actual_size)); + } + } + + return true; +} diff --git a/src/lib/formats/sap_dsk.h b/src/lib/formats/sap_dsk.h new file mode 100644 index 00000000000..5bc86a2d6ef --- /dev/null +++ b/src/lib/formats/sap_dsk.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_FORMATS_SAP_DSK_H +#define MAME_FORMATS_SAP_DSK_H + +#pragma once + +#include "flopimg.h" + +class sap_dsk_format : public floppy_image_format_t +{ +public: + sap_dsk_format() = default; + + virtual const char *name() const noexcept override; + virtual const char *description() const noexcept override; + virtual const char *extensions() const noexcept override; + virtual bool supports_save() const noexcept override; + + virtual int identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const override; + virtual bool load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const override; + +private: + static inline uint16_t accumulate_crc(uint16_t crc, uint8_t data) noexcept; +}; + +extern const sap_dsk_format FLOPPY_SAP_FORMAT; + +#endif // MAME_FORMATS_SAP_DSK_H diff --git a/src/lib/formats/sdf_dsk.cpp b/src/lib/formats/sdf_dsk.cpp index 6e3f1147167..92a6b9fb653 100644 --- a/src/lib/formats/sdf_dsk.cpp +++ b/src/lib/formats/sdf_dsk.cpp @@ -50,8 +50,11 @@ int sdf_format::identify(util::random_read &io, uint32_t form_factor, const std: return 0; } - size_t actual; - io.read_at(0, header, HEADER_SIZE, actual); + auto const [err, actual] = read_at(io, 0, header, HEADER_SIZE); + if (err || (HEADER_SIZE != actual)) + { + return 0; + } int tracks = header[4]; int heads = header[5]; @@ -79,12 +82,11 @@ int sdf_format::identify(util::random_read &io, uint32_t form_factor, const std: bool sdf_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - 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.read_at(0, header, HEADER_SIZE, actual); + read_at(io, 0, header, HEADER_SIZE); // FIXME: check for errors and premature EOF const int tracks = header[4]; const int heads = header[5]; @@ -108,7 +110,7 @@ bool sdf_format::load(util::random_read &io, uint32_t form_factor, const std::ve raw_track_data.clear(); // Read track - io.read_at(HEADER_SIZE + (heads * track + head) * TOTAL_TRACK_SIZE, &track_data[0], TOTAL_TRACK_SIZE, actual); + read_at(io, HEADER_SIZE + (heads * track + head) * TOTAL_TRACK_SIZE, &track_data[0], TOTAL_TRACK_SIZE); // FIXME: check for errors and premature EOF int sector_count = track_data[0]; diff --git a/src/lib/formats/sol_cas.cpp b/src/lib/formats/sol_cas.cpp index 8c05a756042..1a793fb26a8 100644 --- a/src/lib/formats/sol_cas.cpp +++ b/src/lib/formats/sol_cas.cpp @@ -335,7 +335,7 @@ static int sol20_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int sol20_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int sol20_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return sol20_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/sorc_cas.cpp b/src/lib/formats/sorc_cas.cpp index 78417e80fc0..316fca7eaf4 100644 --- a/src/lib/formats/sorc_cas.cpp +++ b/src/lib/formats/sorc_cas.cpp @@ -107,7 +107,7 @@ static int sorcerer_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int sorcerer_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int sorcerer_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return sorcerer_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/spc1000_cas.cpp b/src/lib/formats/spc1000_cas.cpp index e6b3959e2e7..a3830c4a679 100644 --- a/src/lib/formats/spc1000_cas.cpp +++ b/src/lib/formats/spc1000_cas.cpp @@ -89,12 +89,12 @@ static int spc1000_handle_cas(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int spc1000_tap_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int spc1000_tap_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return spc1000_handle_tap(buffer, bytes); } -static int spc1000_cas_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int spc1000_cas_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return spc1000_handle_cas(buffer, bytes); } diff --git a/src/lib/formats/st_dsk.cpp b/src/lib/formats/st_dsk.cpp index 17e0d9efc17..fc105de6fcb 100644 --- a/src/lib/formats/st_dsk.cpp +++ b/src/lib/formats/st_dsk.cpp @@ -79,8 +79,7 @@ bool st_format::load(util::random_read &io, uint32_t form_factor, const std::vec int track_size = sector_count*512; 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); + /*auto const [err, actual] =*/ read_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(atari_st_fcp_get_desc(track, head, head_count, sector_count), track, head, sectors, sector_count, 100000, image); } @@ -116,8 +115,7 @@ bool st_format::save(util::random_read_write &io, const std::vector<uint32_t> &v 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); - size_t actual; - io.write_at((track*head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors } } @@ -152,8 +150,7 @@ bool msa_format::supports_save() const noexcept 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]; - size_t actual; - io.read_at(0, h, 10, actual); + /*auto const [err, actual] =*/ read_at(io, 0, h, 10); // FIXME: check for errors and premature EOF sign = get_u16be(&h[0]); sect = get_u16be(&h[2]); head = get_u16be(&h[4]); @@ -247,12 +244,11 @@ bool msa_format::load(util::random_read &io, uint32_t form_factor, const std::ve for(int track=strack; track <= etrack; track++) { for(int head=0; head <= heads; head++) { - size_t actual; uint8_t th[2]; - io.read_at(pos, th, 2, actual); + read_at(io, pos, th, 2); // FIXME: check for errors and premature EOF pos += 2; int tsize = get_u16be(th); - io.read_at(pos, sectdata, tsize, actual); + read_at(io, pos, sectdata, tsize); // FIXME: check for errors and premature EOF pos += tsize; if(tsize < track_size) { if(!uncompress(sectdata, tsize, track_size)) @@ -301,8 +297,7 @@ bool msa_format::save(util::random_read_write &io, const std::vector<uint32_t> & if(io.seek(0, SEEK_SET)) return false; - size_t actual; - io.write(header, 10, actual); + write(io, header, 10); // FIXME: check for errors uint8_t sectdata[11*512]; uint8_t compdata[11*512]; @@ -315,13 +310,13 @@ bool msa_format::save(util::random_read_write &io, const std::vector<uint32_t> & if(compress(sectdata, track_size, compdata, csize)) { uint8_t th[2]; put_u16be(th, csize); - io.write(th, 2, actual); - io.write(compdata, csize, actual); + write(io, th, 2); // FIXME: check for errors + write(io, compdata, csize); // FIXME: check for errors } else { uint8_t th[2]; put_u16be(th, track_size); - io.write(th, 2, actual); - io.write(sectdata, track_size, actual); + write(io, th, 2); // FIXME: check for errors + write(io, sectdata, track_size); // FIXME: check for errors } } } diff --git a/src/lib/formats/svi_cas.cpp b/src/lib/formats/svi_cas.cpp index 137eaa27a52..6e9a59e6ae9 100644 --- a/src/lib/formats/svi_cas.cpp +++ b/src/lib/formats/svi_cas.cpp @@ -24,7 +24,7 @@ static int cas_size; // FIXME: global variable prevents multiple instances /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int svi_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int svi_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { int cas_pos, samples_pos, n, i; diff --git a/src/lib/formats/svi_dsk.cpp b/src/lib/formats/svi_dsk.cpp index a60491fb20d..4d326542ad5 100644 --- a/src/lib/formats/svi_dsk.cpp +++ b/src/lib/formats/svi_dsk.cpp @@ -83,8 +83,7 @@ bool svi_format::load(util::random_read &io, uint32_t form_factor, const std::ve sectors[i].bad_crc = false; sectors[i].data = §or_data[sector_offset]; - size_t actual; - io.read(sectors[i].data, sector_size, actual); + /*auto const [err, actual] =*/ read(io, sectors[i].data, sector_size); // FIXME: check for errors and premature EOF sector_offset += sector_size; } @@ -113,8 +112,7 @@ bool svi_format::save(util::random_read_write &io, const std::vector<uint32_t> & for (int i = 0; i < 18; i++) { - size_t actual; - io.write(sectors[i + 1].data(), 128, actual); + /*auto const [err, actual] =*/ write(io, sectors[i + 1].data(), 128); // FIXME: check for errors } // rest are mfm tracks @@ -130,8 +128,7 @@ bool svi_format::save(util::random_read_write &io, const std::vector<uint32_t> & for (int i = 0; i < 17; i++) { - size_t actual; - io.write(sectors[i + 1].data(), 256, actual); + /*auto const [err, actual] =*/ write(io, sectors[i + 1].data(), 256); // FIXME: check for errors } } } diff --git a/src/lib/formats/td0_dsk.cpp b/src/lib/formats/td0_dsk.cpp index a9ba54022a0..956bbd002c7 100644 --- a/src/lib/formats/td0_dsk.cpp +++ b/src/lib/formats/td0_dsk.cpp @@ -20,6 +20,7 @@ #include "multibyte.h" #include <cstring> +#include <tuple> #define BUFSZ 512 // new input buffer @@ -330,8 +331,7 @@ int td0dsk_t::data_read(uint8_t *buf, uint16_t size) if (size > image_size - floppy_file_offset) { size = image_size - floppy_file_offset; } - size_t actual; - floppy_file.read_at(floppy_file_offset, buf, size, actual); + /*auto const [err, actual] =*/ read_at(floppy_file, floppy_file_offset, buf, size); // FIXME: check for errors and premature EOF floppy_file_offset += size; return size; } @@ -810,10 +810,13 @@ const char *td0_format::extensions() const noexcept int td0_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - size_t actual; uint8_t h[7]; + auto const [err, actual] = read_at(io, 0, h, 7); // FIXME: does this need to read 7 bytes? it only check 2 bytes. Also check for premature EOF. + if(err) + { + return 0; + } - io.read_at(0, h, 7, actual); if(((h[0] == 'T') && (h[1] == 'D')) || ((h[0] == 't') && (h[1] == 'd'))) { return FIFID_SIGN; @@ -823,6 +826,7 @@ int td0_format::identify(util::random_read &io, uint32_t form_factor, const std: bool td0_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { + std::error_condition err; size_t actual; int track_count = 0; int head_count = 0; @@ -830,9 +834,10 @@ bool td0_format::load(util::random_read &io, uint32_t form_factor, const std::ve int offset = 0; 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[12]; - if(io.read_at(0, header, 12, actual) || actual != 12) + uint8_t header[12]; + std::tie(err, actual) = read_at(io, 0, header, 12); + if(err || (actual != 12)) return false; head_count = header[9]; @@ -849,7 +854,8 @@ bool td0_format::load(util::random_read &io, uint32_t form_factor, const std::ve uint64_t image_size; if(io.length(image_size)) return false; - if(io.read_at(12, &imagebuf[0], image_size - 12, actual) || actual != (image_size - 12)) + std::tie(err, actual) = read_at(io, 12, &imagebuf[0], image_size - 12); + if(err || (actual != (image_size - 12))) return false; } diff --git a/src/lib/formats/thom_cas.cpp b/src/lib/formats/thom_cas.cpp index 02bab6217fe..f6f9e317d4f 100644 --- a/src/lib/formats/thom_cas.cpp +++ b/src/lib/formats/thom_cas.cpp @@ -58,6 +58,8 @@ static uint8_t* to7_k7_bits; and so, is used by emulators that bypass the BIOS routine. It is generally hacked from the raw image more or less by hand (in particular, to by-pass special loaders and copy-protection schemes). + Many of these hacks use emulator-exclusive 6809 instructions and will + not work in MAME. As we run the original BIOS routine, we need to hack back the k7 file into the original stream. @@ -462,7 +464,8 @@ static cassette_image::error mo5_k5_load( cassette_image *cass ) size_t size = cass->image_size( ), pos = 0; int i, sz, sz2, hbit = 0; uint8_t typ, block[264], sum; - int invalid = 0, hbitsize = 0, dcmoto = 0; + int invalid = 0, hbitsize = 0; + bool dcmoto = false, dcmoto_old = false; LOG (( "mo5_k5_load: start conversion, size=%li\n", (long)size )); PRINT (( "mo5_k5_load: open cassette, length: %li bytes\n", (long) size )); @@ -553,7 +556,9 @@ static cassette_image::error mo5_k5_load( cassette_image *cass ) cass->image_read( block, pos, 6 ); if ( ! memcmp( block, "DCMOTO", 6 ) || ! memcmp( block, "DCMO5", 5 ) || ! memcmp( block, "DCMO6", 5 ) ) - dcmoto = 1; + dcmoto = true; + if ( block[0] == 0xdc && block[1] == 0x01 ) + dcmoto_old = true; /* loop over regular blocks */ while ( pos < size ) @@ -574,6 +579,12 @@ static cassette_image::error mo5_k5_load( cassette_image *cass ) pos += 5; } } + else if ( dcmoto_old ) + { + cass->image_read( block, pos, 1 ); + if ( block[0] == 0xdc ) + pos++; + } /* skip 0x01 filler */ for ( sz = 0; pos < size; pos++, sz++ ) @@ -693,7 +704,12 @@ static cassette_image::error mo5_k5_load( cassette_image *cass ) pos -= sz; goto rebounce; } - if ( invalid < 10 && sz > 6 && ( (in == 0x3c && in2 == 0x5a) || (in == 0xc3 && in2 == 0x5a) || (in == 0xc3 && in2 == 0x3c) || (in == 0x87 && in2 == 0x4a) ) ) + if ( invalid < 10 && sz > 6 && + ( (in == 0x3c && in2 == 0x5a) || + (in == 0xc3 && in2 == 0x5a) || + (in == 0xc3 && in2 == 0x3c) || + (in == 0x87 && in2 == 0x4a) || + (in == 0x3c && in2 == 0x55) ) ) // Androïdes { /* special block found */ K5_FILL_0( 1200 ); diff --git a/src/lib/formats/thom_dsk.cpp b/src/lib/formats/thom_dsk.cpp index ad2e4495ca2..3399a1aa487 100644 --- a/src/lib/formats/thom_dsk.cpp +++ b/src/lib/formats/thom_dsk.cpp @@ -50,6 +50,12 @@ const thomson_525_format::format thomson_525_format::formats[] = { {} }; +int thomson_525_format::get_image_offset(const format &f, int head, int track) const +{ + return (track + (head ? f.track_count : 0)) * compute_track_size(f); +} + + thomson_35_format::thomson_35_format() : wd177x_format(formats) { @@ -70,6 +76,8 @@ const char *thomson_35_format::extensions() const noexcept return "fd"; } +// 1280K .fd images exist but are not supported. They represent a notional type +// of 4-sided disk that can be inserted into 2 drives at once. const thomson_35_format::format thomson_35_format::formats[] = { { floppy_image::FF_35, floppy_image::SSDD, floppy_image::MFM, @@ -90,5 +98,10 @@ const thomson_35_format::format thomson_35_format::formats[] = { {} }; +int thomson_35_format::get_image_offset(const format &f, int head, int track) const +{ + return (track + (head ? f.track_count : 0)) * compute_track_size(f); +} + const thomson_525_format FLOPPY_THOMSON_525_FORMAT; const thomson_35_format FLOPPY_THOMSON_35_FORMAT; diff --git a/src/lib/formats/thom_dsk.h b/src/lib/formats/thom_dsk.h index 52927f15de8..09ea1cbec0c 100644 --- a/src/lib/formats/thom_dsk.h +++ b/src/lib/formats/thom_dsk.h @@ -16,6 +16,8 @@ public: virtual const char *description() const noexcept override; virtual const char *extensions() const noexcept override; + int get_image_offset(const format &f, int head, int track) const override; + private: static const format formats[]; }; @@ -29,6 +31,8 @@ public: virtual const char *description() const noexcept override; virtual const char *extensions() const noexcept override; + int get_image_offset(const format &f, int head, int track) const override; + private: static const format formats[]; }; diff --git a/src/lib/formats/ti99_dsk.cpp b/src/lib/formats/ti99_dsk.cpp index 64b8d81aa67..4cca5bdb996 100644 --- a/src/lib/formats/ti99_dsk.cpp +++ b/src/lib/formats/ti99_dsk.cpp @@ -954,8 +954,7 @@ int ti99_sdf_format::identify(util::random_read &io, uint32_t form_factor, const { // Read first sector (Volume Information Block) ti99vib vib; - size_t actual; - io.read_at(0, &vib, sizeof(ti99vib), actual); + /*auto const [err, actual] =*/ read_at(io, 0, &vib, sizeof(ti99vib)); // FIXME: check for errors and premature EOF // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) @@ -993,8 +992,7 @@ void ti99_sdf_format::determine_sizes(util::random_read &io, int& cell_size, int // Read first sector ti99vib vib; - size_t actual; - io.read_at(0, &vib, sizeof(ti99vib), actual); + /*auto const [err, actual] =*/ read_at(io, 0, &vib, sizeof(ti99vib)); // FIXME: check for errors and premature EOF // Check from contents if ((vib.id[0]=='D')&&(vib.id[1]=='S')&&(vib.id[2]=='K')) @@ -1079,8 +1077,7 @@ void ti99_sdf_format::load_track(util::random_read &io, uint8_t *sectordata, int int logicaltrack = (head==0)? track : (2*trackcount - track - 1); int position = logicaltrack * get_track_size(sectorcount); - size_t actual; - io.read_at(position, sectordata, sectorcount*SECTOR_SIZE, actual); + /*auto const [err, actual] =*/ read_at(io, position, sectordata, sectorcount*SECTOR_SIZE); // FIXME: check for errors and premature EOF // Interleave and skew int interleave = 7; @@ -1158,8 +1155,7 @@ void ti99_sdf_format::write_track(util::random_read_write &io, uint8_t *sectorda { 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); - size_t actual; - io.write_at(trackoffset + sector[i] * SECTOR_SIZE, buf, SECTOR_SIZE, actual); + /*auto const [err, actual] =*/ write_at(io, trackoffset + sector[i] * SECTOR_SIZE, buf, SECTOR_SIZE); // FIXME: check for errors } } @@ -1246,8 +1242,7 @@ int ti99_tdf_format::identify(util::random_read &io, uint32_t form_factor, const LOGMASKED(LOG_INFO, "[ti99_dsk] Image file length matches TDF\n"); // Fetch track 0 - size_t actual; - io.read_at(0, fulltrack, get_track_size(sector_count), actual); + /*auto const [err, actual] =*/ read_at(io, 0, fulltrack, get_track_size(sector_count)); // FIXME: check for errors and premature EOF if (sector_count == 9) { @@ -1358,12 +1353,11 @@ void ti99_tdf_format::determine_sizes(util::random_read &io, int& cell_size, int */ 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) const { - 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.read_at(0, fulltrack, 100, actual); + read_at(io, 0, fulltrack, 100); // FIXME: check for errors and premature EOF int offset = 0; int tracksize = get_track_size(sectorcount); @@ -1404,7 +1398,7 @@ void ti99_tdf_format::load_track(util::random_read &io, uint8_t *sectordata, int int base = (head * trackcount + track) * tracksize; int position = 0; - io.read_at(base, fulltrack, tracksize, actual); + read_at(io, base, fulltrack, tracksize); // FIXME: check for errors and premature EOF for (int i=0; i < sectorcount; i++) { @@ -1506,8 +1500,7 @@ void ti99_tdf_format::write_track(util::random_read_write &io, uint8_t *sectorda for (int i=0; i < param[WGAP3]; i++) trackdata[pos++] = param[WGAPBYTE]; } for (int i=0; i < param[WGAP4]; i++) trackdata[pos++] = param[WGAPBYTE]; - size_t actual; - io.write_at(offset, trackdata, get_track_size(sector_count), actual); + /*auto const [err, actual] =*/ write_at(io, offset, trackdata, get_track_size(sector_count)); // FIXME: check for errors } int ti99_tdf_format::get_track_size(int sector_count) const diff --git a/src/lib/formats/trd_dsk.cpp b/src/lib/formats/trd_dsk.cpp index 4ec6d4a962a..cf1a7f00445 100644 --- a/src/lib/formats/trd_dsk.cpp +++ b/src/lib/formats/trd_dsk.cpp @@ -12,6 +12,8 @@ #include "ioprocs.h" +#include <tuple> + trd_format::trd_format() : wd177x_format(formats) { @@ -51,16 +53,19 @@ int trd_format::find_size(util::random_read &io, uint32_t form_factor, const std { index = i; // at least size match, save it for the case if there will be no exact matches + std::error_condition err; size_t actual; uint8_t sectdata[0x100]; if (f.encoding == floppy_image::MFM) - io.read_at(0x800, sectdata, 0x100, actual); + std::tie(err, actual) = read_at(io, 0x800, sectdata, 0x100); else { - io.read_at(0x100, sectdata, 0x100, actual); + std::tie(err, actual) = read_at(io, 0x100, sectdata, 0x100); for (int i = 0; i < 0x100; i++) sectdata[i] ^= 0xff; } + if (err || (0x100 != actual)) + continue; uint8_t disktype = sectdata[0xe3]; // 16 - DS80, 17 - DS40, 18 - SS80, 19 - SS40 if (disktype < 0x16 || disktype > 0x19) diff --git a/src/lib/formats/trs80_dsk.cpp b/src/lib/formats/trs80_dsk.cpp index 511d9fdfbf1..f670273a5af 100644 --- a/src/lib/formats/trs80_dsk.cpp +++ b/src/lib/formats/trs80_dsk.cpp @@ -146,9 +146,9 @@ int jv3_format::identify(util::random_read &io, uint32_t form_factor, const std: if (image_size < 0x2200) return 0; // too small, silent return - std::vector<uint8_t> data(image_size); - size_t actual; - io.read_at(0, data.data(), image_size, actual); + auto const [err, data, actual] = read_at(io, 0, image_size); + if (err || (actual != image_size)) + return 0; const uint32_t entries = 2901; const uint32_t header_size = entries *3 +1; @@ -238,9 +238,9 @@ bool jv3_format::load(util::random_read &io, uint32_t form_factor, const std::ve 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); + auto const [err, data, actual] = read_at(io, 0, image_size); + if (err || (actual != image_size)) + return 0; const uint32_t entries = 2901; const uint32_t header_size = entries *3 +1; bool is_dd = false, is_ds = false; @@ -365,13 +365,14 @@ bool jv3_format::save(util::random_read_write &io, const std::vector<uint32_t> & { // If the disk already exists, find out if it's writable uint64_t image_size; - if (!io.length(image_size)) + if (!io.length(image_size) && (image_size >= 0x2200)) { - 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 + uint8_t flag; + auto const [err, actual] = read_at(io, 0x21ff, &flag, 1); + if (err || (1 != actual)) // TODO: should we save over the top if we couldn’t read the read-only flag? + return false; + if (flag == 0) + return false; // disk is read-only } } @@ -413,8 +414,7 @@ bool jv3_format::save(util::random_read_write &io, const std::vector<uint32_t> & header[sect_ptr++] = track; header[sect_ptr++] = i; header[sect_ptr++] = head ? 0x10 : 0; - size_t actual; - io.write_at(data_ptr, &dummy[0], 256, actual); + /*auto const [err, actual] =*/ write_at(io, data_ptr, &dummy[0], 256); // FIXME: check for errors data_ptr += 256; } } @@ -435,16 +435,14 @@ bool jv3_format::save(util::random_read_write &io, const std::vector<uint32_t> & flags |= (sectors[i].size() >> 8) ^1; flags |= head ? 0x10 : 0; header[sect_ptr++] = flags; - size_t actual; - io.write_at(data_ptr, sectors[i].data(), sectors[i].size(), actual); + /*auto const [err, actual] =*/ write_at(io, data_ptr, sectors[i].data(), sectors[i].size()); // FIXME: check for errors data_ptr += sectors[i].size(); } } } } // Save the header - size_t actual; - io.write_at(0, header, 0x2200, actual); + /*auto const [err, actual] =*/ write_at(io, 0, header, 0x2200); // FIXME: check for errors return true; } diff --git a/src/lib/formats/trs_cas.cpp b/src/lib/formats/trs_cas.cpp index 8b1ede7ec81..2648c536320 100644 --- a/src/lib/formats/trs_cas.cpp +++ b/src/lib/formats/trs_cas.cpp @@ -174,7 +174,7 @@ static int trs80m3_handle_cas(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int trs80_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int trs80_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { if (cas_size && (bytes[0] == 0x55)) return trs80m3_handle_cas( buffer, bytes ); diff --git a/src/lib/formats/tzx_cas.cpp b/src/lib/formats/tzx_cas.cpp index 4d14e567453..f758c1b31e6 100644 --- a/src/lib/formats/tzx_cas.cpp +++ b/src/lib/formats/tzx_cas.cpp @@ -72,7 +72,7 @@ static void toggle_wave_data(void) static void tzx_cas_get_blocks( const uint8_t *casdata, int caslen ) { - int pos = sizeof(TZX_HEADER) + 2; + uint32_t pos = sizeof(TZX_HEADER) + 2; int max_block_count = INITIAL_MAX_BLOCK_COUNT; int loopcount = 0, loopoffset = 0; blocks = (uint8_t**)malloc(max_block_count * sizeof(uint8_t*)); @@ -192,7 +192,14 @@ static void tzx_cas_get_blocks( const uint8_t *casdata, int caslen ) break; } - block_count++; + if (pos > caslen) + { + LOG_FORMATS("Block %d(ID=%d) with wrong length discarded\n", block_count, blocktype); + } + else + { + block_count++; + } } } @@ -779,7 +786,7 @@ cleanup: return -1; } -static int tzx_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) +static int tzx_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int16_t *p = buffer; int size = 0; @@ -788,7 +795,7 @@ static int tzx_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) return size; } -static int cdt_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) +static int cdt_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { int16_t *p = buffer; int size = 0; @@ -797,72 +804,114 @@ static int cdt_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) return size; } -static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen ) +static int tap_cas_to_wav_size(const uint8_t *casdata, int caslen) { + /* + TAP Header: + | 0 | W | Length of Data Block (N) | -+ + | 2 | B | Flag Byte | -+ + | 3 | B*(N-2) | Data | | Data Block + | N+1 | B | XOR Checksum of [2..N] | -+ + */ + int size = 0; const uint8_t *p = casdata; - while (p < casdata + caslen) + while (caslen > 2) { int data_size = get_u16le(&p[0]); - int pilot_length = (p[2] == 0x00) ? 8063 : 3223; - LOG_FORMATS("tap_cas_to_wav_size: Handling TAP block containing 0x%X bytes", data_size); p += 2; + caslen -= 2; + if (caslen < data_size) + { + LOG_FORMATS("tap_cas_to_wav_size: Requested 0x%X bytes but only 0x%X available.\n", data_size, caslen); + data_size = caslen; + } + caslen -= data_size; + + // Data Block + LOG_FORMATS("tap_cas_to_wav_size: Handling TAP block containing 0x%X bytes", data_size); + const int pilot_length = (p[0] == 0x00) ? 8063 : 3223; size += tzx_cas_handle_block(nullptr, p, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); - LOG_FORMATS(", total size is now: %d\n", size); + LOG_FORMATS(", total size is now: %d", size); + + // Validate Checksum + const uint8_t checksum = p[data_size - 1]; + LOG_FORMATS(", checksum 0x%X\n", checksum); + uint8_t check = 0x00; + for(int i = 0; i < (data_size - 1); i++) + { + check ^= p[i]; + } + if (check != checksum) + { + osd_printf_warning("tap_cas_to_wav_size: wrong checksum 0x%X\n", check); + } + p += data_size; } return size; } -static int tap_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) +static int tap_cas_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int bytes_length) { int16_t *p = buffer; int size = 0; - while (size < length) + int block = 0; + while (bytes_length > 2) { int data_size = get_u16le(&bytes[0]); - int pilot_length = (bytes[2] == 0x00) ? 8063 : 3223; - LOG_FORMATS("tap_cas_fill_wave: Handling TAP block containing 0x%X bytes\n", data_size); bytes += 2; + bytes_length -= 2; + + LOG_FORMATS("tap_cas_fill_wave: Handling TAP block containing 0x%X bytes\n", data_size); + if (bytes_length < data_size) + { + osd_printf_warning("BAD Image: block #%d required %d byte(s), but only %d available\n", block, data_size, bytes_length); + data_size = bytes_length; // Take as much as we can. + } + bytes_length -= data_size; + + int pilot_length = (bytes[0] == 0x00) ? 8063 : 3223; size += tzx_cas_handle_block(&p, bytes, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8); bytes += data_size; + ++block; } return size; } static const cassette_image::LegacyWaveFiller tzx_legacy_fill_wave = { - tzx_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + tzx_cas_fill_wave, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tzx_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0, // trailer_samples }; static const cassette_image::LegacyWaveFiller tap_legacy_fill_wave = { - tap_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tap_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + tap_cas_fill_wave, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tap_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0 // trailer_samples }; static const cassette_image::LegacyWaveFiller cdt_legacy_fill_wave = { - cdt_cas_fill_wave, /* fill_wave */ - -1, /* chunk_size */ - 0, /* chunk_samples */ - tzx_cas_to_wav_size, /* chunk_sample_calc */ - TZX_WAV_FREQUENCY, /* sample_frequency */ - 0, /* header_samples */ - 0 /* trailer_samples */ + cdt_cas_fill_wave, // fill_wave + -1, // chunk_size + 0, // chunk_samples + tzx_cas_to_wav_size, // chunk_sample_calc + TZX_WAV_FREQUENCY, // sample_frequency + 0, // header_samples + 0 // trailer_samples }; static cassette_image::error tzx_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) diff --git a/src/lib/formats/uef_cas.cpp b/src/lib/formats/uef_cas.cpp index f284af43035..02f150915a7 100644 --- a/src/lib/formats/uef_cas.cpp +++ b/src/lib/formats/uef_cas.cpp @@ -247,7 +247,7 @@ static int16_t* uef_cas_fill_bit( uint8_t loops, int16_t *buffer, bool bit ) return buffer; } -static int uef_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) +static int uef_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int ) { if ( bytes[0] == 0x1f && bytes[1] == 0x8b ) { if ( gz_ptr == nullptr ) { @@ -264,16 +264,16 @@ static int uef_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) int chunk_type = get_u16le( &bytes[pos] ); int chunk_length = get_u32le( &bytes[pos+2] ); - uint32_t baud_length, j; - uint8_t i, *c; + uint32_t baud_length; + const uint8_t *c; pos += 6; switch( chunk_type ) { case 0x0100: /* implicit start/stop bit data block */ case 0x0104: // used by atom dumps, looks like normal data - for( j = 0; j < chunk_length; j++ ) { + for( uint32_t j = 0; j < chunk_length; j++ ) { uint8_t byte = bytes[pos+j]; p = uef_cas_fill_bit( loops, p, 0 ); - for( i = 0; i < 8; i++ ) { + for( uint8_t i = 0; i < 8; i++ ) { p = uef_cas_fill_bit( loops, p, (byte >> i) & 1 ); } p = uef_cas_fill_bit( loops, p, 1 ); @@ -285,11 +285,10 @@ static int uef_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) LOG_FORMATS( "Unsupported chunk type: %04x\n", chunk_type ); break; case 0x0102: /* explicit tape data block */ - j = ( chunk_length * 10 ) - bytes[pos]; c = bytes + pos; - while( j ) { + for( uint32_t j = ( chunk_length * 10 ) - bytes[pos]; j; ) { uint8_t byte = *c; - for( i = 0; i < 8 && i < j; i++ ) { + for( uint8_t i = 0; i < 8 && i < j; i++ ) { p = uef_cas_fill_bit( loops, p, (byte >> i) & 1 ); j--; } @@ -311,7 +310,7 @@ static int uef_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) } break; case 0x0116: /* floating point gap */ - for( baud_length = (get_uef_float(bytes+pos)*UEF_WAV_FREQUENCY); baud_length; baud_length-- ) { + for( baud_length = (get_uef_float(bytes + pos)*UEF_WAV_FREQUENCY); baud_length; baud_length-- ) { *p = WAVE_NULL; p++; length -= 1; } diff --git a/src/lib/formats/uniflex_dsk.cpp b/src/lib/formats/uniflex_dsk.cpp index 0143bf8cf0e..063d3c877f9 100644 --- a/src/lib/formats/uniflex_dsk.cpp +++ b/src/lib/formats/uniflex_dsk.cpp @@ -53,8 +53,9 @@ int uniflex_format::find_size(util::random_read &io, uint32_t form_factor, const // Look at the SIR sector, the second sector. uint8_t sir[192]; - size_t actual; - io.read_at(1 * 512, sir, sizeof(sir), actual); + auto const [err, actual] = read_at(io, 1 * 512, sir, sizeof(sir)); // FIXME: check for premature EOF + if (err) + return -1; uint16_t fdn_block_count = get_u16be(&sir[0x10]); uint32_t last_block_number = get_u24be(&sir[0x12]); diff --git a/src/lib/formats/upd765_dsk.cpp b/src/lib/formats/upd765_dsk.cpp index f3f08f37b4e..589ab1e1666 100644 --- a/src/lib/formats/upd765_dsk.cpp +++ b/src/lib/formats/upd765_dsk.cpp @@ -231,8 +231,7 @@ bool upd765_format::load(util::random_read &io, uint32_t form_factor, const std: 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); - size_t actual; - io.read_at((track*f.head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ read_at(io, (track*f.head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(desc, track, head, sectors, f.sector_count, total_size, image); } @@ -345,20 +344,19 @@ bool upd765_format::save(util::random_read_write &io, const std::vector<uint32_t if(chosen_candidate == -1) chosen_candidate = 0; - const format &f = formats[chosen_candidate]; int track_size = compute_track_size(f); uint8_t sectdata[40*512]; desc_s sectors[40]; - for(int track=0; track < f.track_count; track++) + 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); extract_sectors(image, f, sectors, track, head); - size_t actual; - io.write_at((track*f.head_count + head)*track_size, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, (track*f.head_count + head)*track_size, sectdata, track_size); // FIXME: check for errors } + } return true; } diff --git a/src/lib/formats/vdk_dsk.cpp b/src/lib/formats/vdk_dsk.cpp index e47d3502981..02e25ec5df9 100644 --- a/src/lib/formats/vdk_dsk.cpp +++ b/src/lib/formats/vdk_dsk.cpp @@ -36,9 +36,10 @@ const char *vdk_format::extensions() const noexcept int vdk_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { - size_t actual; uint8_t id[2]; - io.read_at(0, id, 2, actual); + auto const [err, actual] = read_at(io, 0, id, 2); + if (err || (2 != actual)) + return 0; if (id[0] == 'd' && id[1] == 'k') return FIFID_SIGN; @@ -48,12 +49,11 @@ int vdk_format::identify(util::random_read &io, uint32_t form_factor, const std: bool vdk_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { - size_t actual; if (io.seek(0, SEEK_SET)) return false; uint8_t header[0x100]; - io.read(header, 0x100, actual); + read(io, header, 0x100); // FIXME: check for errors and premature EOF int const header_size = header[3] * 0x100 + header[2]; int const track_count = header[8]; @@ -81,7 +81,7 @@ bool vdk_format::load(util::random_read &io, uint32_t form_factor, const std::ve sectors[i].bad_crc = false; sectors[i].data = §or_data[sector_offset]; - io.read(sectors[i].data, SECTOR_SIZE, actual); + read(io, sectors[i].data, SECTOR_SIZE); // FIXME: check for errors and premature EOF sector_offset += SECTOR_SIZE; } @@ -95,7 +95,6 @@ bool vdk_format::load(util::random_read &io, uint32_t form_factor, const std::ve bool vdk_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const { - size_t actual; if (io.seek(0, SEEK_SET)) return false; @@ -118,7 +117,7 @@ bool vdk_format::save(util::random_read_write &io, const std::vector<uint32_t> & header[10] = 0; header[11] = 0; - io.write(header, sizeof(header), actual); + write(io, header, sizeof(header)); // FIXME: check for errors // write disk data for (int track = 0; track < track_count; track++) @@ -129,7 +128,7 @@ bool vdk_format::save(util::random_read_write &io, const std::vector<uint32_t> & auto sectors = extract_sectors_from_bitstream_mfm_pc(bitstream); for (int i = 0; i < SECTOR_COUNT; i++) - io.write(sectors[FIRST_SECTOR_ID + i].data(), SECTOR_SIZE, actual); + write(io, sectors[FIRST_SECTOR_ID + i].data(), SECTOR_SIZE); // FIXME: check for errors } } diff --git a/src/lib/formats/vg5k_cas.cpp b/src/lib/formats/vg5k_cas.cpp index fcdb9ba7f02..724a4889229 100644 --- a/src/lib/formats/vg5k_cas.cpp +++ b/src/lib/formats/vg5k_cas.cpp @@ -184,7 +184,7 @@ static int vg5k_handle_tap(int16_t *buffer, const uint8_t *casdata) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int vg5k_k7_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int vg5k_k7_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return vg5k_handle_tap(buffer, bytes); } diff --git a/src/lib/formats/vgi_dsk.cpp b/src/lib/formats/vgi_dsk.cpp index ae6cd53018e..a86ffdefb75 100644 --- a/src/lib/formats/vgi_dsk.cpp +++ b/src/lib/formats/vgi_dsk.cpp @@ -18,8 +18,8 @@ http://www.bitsavers.org/pdf/micropolis/metafloppy/1084-01_1040_1050_Users_Manua #include <cstring> -static const int track_size = 100'000; -static const int half_bitcell_size = 2000; +static constexpr int TRACK_SIZE = 100'000; +static constexpr int HALF_BITCELL_SIZE = 2000; micropolis_vgi_format::micropolis_vgi_format() : floppy_image_format_t() { @@ -32,10 +32,10 @@ struct format { }; static const format formats[] = { - {1, 35, floppy_image::SSDD}, // MOD-I - {2, 35, floppy_image::DSDD}, - {1, 77, floppy_image::SSQD}, // MOD-II - {2, 77, floppy_image::DSQD}, + {1, 35, floppy_image::SSDD16}, // MOD-I + {2, 35, floppy_image::DSDD16}, + {1, 77, floppy_image::SSQD16}, // MOD-II + {2, 77, floppy_image::DSQD16}, {} }; @@ -76,14 +76,14 @@ bool micropolis_vgi_format::load(util::random_read &io, uint32_t form_factor, co for (int track = 0; track < fmt.track_count; track++) { for (int sector = 0; sector < 16; sector++) { for (int i = 0; i < 40; i++) - mfm_w(buf, 8, 0, half_bitcell_size); - std::size_t actual; - if (io.read(sector_bytes, std::size(sector_bytes), actual)) + mfm_w(buf, 8, 0, HALF_BITCELL_SIZE); + auto const [err, actual] = read(io, sector_bytes, std::size(sector_bytes)); + if (err || (actual != std::size(sector_bytes))) return false; for (int i = 0; i < std::size(sector_bytes); i++) - mfm_w(buf, 8, sector_bytes[i], half_bitcell_size); - while (buf.size() < track_size/16 * (sector+1)) - mfm_w(buf, 8, 0, half_bitcell_size); + mfm_w(buf, 8, sector_bytes[i], HALF_BITCELL_SIZE); + while (buf.size() < TRACK_SIZE/16 * (sector+1)) + mfm_w(buf, 8, 0, HALF_BITCELL_SIZE); } generate_track_from_levels(track, head, buf, 0, image); buf.clear(); @@ -116,9 +116,9 @@ bool micropolis_vgi_format::save(util::random_read_write &io, const std::vector< uint8_t sector_bytes[275]; for (int head = 0; head < fmt.head_count; head++) { for (int track = 0; track < fmt.track_count; track++) { - std::vector<bool> bitstream = generate_bitstream_from_track(track, head, half_bitcell_size, image); + std::vector<bool> bitstream = generate_bitstream_from_track(track, head, HALF_BITCELL_SIZE, image); for (int sector = 0; sector < 16; sector++) { - int sector_start = track_size/16 * sector; + int sector_start = TRACK_SIZE/16 * sector; uint32_t pos = sector_start + 512 - 16; uint16_t shift_reg = 0; while (pos < sector_start + 60*16 && pos < bitstream.size()) { @@ -134,8 +134,8 @@ bool micropolis_vgi_format::save(util::random_read_write &io, const std::vector< memset(sector_bytes, 0, std::size(sector_bytes)); } - std::size_t actual; - if (io.write(sector_bytes, std::size(sector_bytes), actual)) + auto const [err, actual] = write(io, sector_bytes, std::size(sector_bytes)); + if (err) return false; } } diff --git a/src/lib/formats/victor9k_dsk.cpp b/src/lib/formats/victor9k_dsk.cpp index a0fdaedab5a..803c75303d8 100644 --- a/src/lib/formats/victor9k_dsk.cpp +++ b/src/lib/formats/victor9k_dsk.cpp @@ -136,12 +136,12 @@ const char *victor9k_format::extensions() const noexcept int victor9k_format::find_size(util::random_read &io) { uint64_t size; - if(io.length(size)) + if (io.length(size)) return -1; - for(int i=0; formats[i].sector_count; i++) { + 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) + if(size == uint32_t(f.sector_count*f.sector_base_size)) return i; } @@ -155,7 +155,7 @@ int victor9k_format::find_size(util::random_read &io, uint32_t form_factor) int victor9k_format::identify(const floppy_image &image) { - for(int i=0; formats[i].form_factor; i++) { + for (int i = 0; formats[i].form_factor; i++) { const format &f = formats[i]; if(f.variant == image.get_variant()) return i; @@ -291,7 +291,7 @@ void victor9k_format::build_sector_description(const format &f, uint8_t *sectdat bool victor9k_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const { int const type = find_size(io, form_factor); - if(type == -1) + if (type == -1) return false; const format &f = formats[type]; @@ -300,15 +300,12 @@ bool victor9k_format::load(util::random_read &io, uint32_t form_factor, const st f.head_count, f.sector_count); uint64_t size; - if(io.length(size)) + if (io.length(size)) return false; - std::vector<uint8_t> img; - try { img.resize(size); } - catch (...) { return false; } - - size_t actual; - io.read_at(0, &img[0], size, actual); + auto const [err, img, actual] = read_at(io, 0, size); + if (err || (actual != size)) + return false; log_boot_sector(&img[0]); @@ -449,17 +446,17 @@ bool victor9k_format::save(util::random_read_write &io, const std::vector<uint32 { int type = victor9k_format::identify(image); uint64_t size; - io.length(size); + io.length(size); // FIXME: check for errors osd_printf_verbose("save type: %01d, size: %d\n", type, size); - if(type == -1) + if (type == -1) return false; const format &f = formats[type]; osd_printf_verbose("save Heads: %01d Tracks: %02d Sectors/track head[1]track[1]: %02d\n ", f.head_count, f.track_count, sectors_per_track[1][1]); - for(int head=0; head < f.head_count; head++) { + for (int head = 0; head < f.head_count; head++) { for(int track=0; track < f.track_count; track++) { int sector_count = sectors_per_track[head][track]; int track_size = compute_track_size(f, head, track); @@ -471,8 +468,7 @@ bool victor9k_format::save(util::random_read_write &io, const std::vector<uint32 build_sector_description(f, sectdata, 0, sectors, sector_count); extract_sectors(image, f, sectors, track, head, sector_count); - size_t actual; - io.write_at(offset, sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, offset, sectdata, track_size); // FIXME: check for errors } } @@ -481,7 +477,6 @@ bool victor9k_format::save(util::random_read_write &io, const std::vector<uint32 void victor9k_format::extract_sectors(const floppy_image &image, const format &f, desc_s *sdesc, int track, int head, int sector_count) { - // Extract the sectors auto bitstream = generate_bitstream_from_track(track, head, cell_size[speed_zone[head][track]], image); auto sectors = extract_sectors_from_bitstream_victor_gcr5(bitstream); @@ -493,14 +488,14 @@ void victor9k_format::extract_sectors(const floppy_image &image, const format &f } } - for(int i=0; i<sector_count; i++) { + for (int i = 0; i<sector_count; i++) { desc_s &ds = sdesc[i]; const auto &data = sectors[ds.sector_id]; osd_printf_verbose("Head: %01d TracK: %02d Total Sectors: %02d Current Sector: %02d ", head, track, sector_count, i); - if(data.empty()) { + if (data.empty()) { memset((uint8_t *)ds.data, 0, ds.size); - } else if(data.size() < ds.size) { + } else if (data.size() < ds.size) { memcpy((uint8_t *)ds.data, data.data(), data.size() - 1); memset((uint8_t *)ds.data + data.size() - 1, 0, data.size() - ds.size); osd_printf_verbose("data.size(): %01d\n", data.size()); diff --git a/src/lib/formats/vt_cas.cpp b/src/lib/formats/vt_cas.cpp index 046e97880d8..2052647bfd8 100644 --- a/src/lib/formats/vt_cas.cpp +++ b/src/lib/formats/vt_cas.cpp @@ -8,7 +8,7 @@ #define SILENCE 8000 -static int generic_fill_wave(int16_t *buffer, int length, uint8_t *code, int bitsamples, int bytesamples, int lo, int16_t *(*fill_wave_byte)(int16_t *buffer, int byte)) +static int generic_fill_wave(int16_t *buffer, int length, const uint8_t *code, int bitsamples, int bytesamples, int lo, int16_t *(*fill_wave_byte)(int16_t *buffer, int byte)) { static int nullbyte; @@ -90,7 +90,7 @@ static int16_t *vtech1_fill_wave_byte(int16_t *buffer, int byte) return buffer; } -static int vtech1_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code) +static int vtech1_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *code, int) { return generic_fill_wave(buffer, length, code, V1_BITSAMPLES, V1_BYTESAMPLES, V1_LO, vtech1_fill_wave_byte); } @@ -185,7 +185,7 @@ static int16_t *vtech2_fill_wave_byte(int16_t *buffer, int byte) return buffer; } -static int vtech2_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code) +static int vtech2_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *code, int) { return generic_fill_wave(buffer, length, code, VT2_BITSAMPLES, VT2_BYTESAMPLES, VT2_LO, vtech2_fill_wave_byte); } diff --git a/src/lib/formats/vt_dsk.cpp b/src/lib/formats/vt_dsk.cpp index 202ec784187..da7e450b673 100644 --- a/src/lib/formats/vt_dsk.cpp +++ b/src/lib/formats/vt_dsk.cpp @@ -21,6 +21,7 @@ void vtech_common_format::wbit(std::vector<uint32_t> &buffer, uint32_t &pos, bool bit) { + buffer.push_back(pos | floppy_image::MG_F); if(bit) { pos += 2237; buffer.push_back(pos | floppy_image::MG_F); @@ -35,13 +36,13 @@ void vtech_common_format::wbyte(std::vector<uint32_t> &buffer, uint32_t &pos, ui wbit(buffer, pos, (byte >> i) & 1); } -void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, floppy_image &image) +void vtech_common_format::image_to_flux(const uint8_t *bdata, size_t size, floppy_image &image) { static const uint8_t sector_map[16] = { 0x0, 0xb, 0x6, 0x1, 0xc, 0x7, 0x2, 0xd, 0x8, 0x3, 0xe, 0x9, 0x4, 0xf, 0xa, 0x5 }; - for(int track = 0; track != 40; track ++) { + for(int track = 0; track != 40; track++) { uint32_t pos = 0; std::vector<uint32_t> &buffer = image.get_buffer(track, 0); buffer.clear(); @@ -49,7 +50,7 @@ void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, flopp // One window of pad at the start to avoid problems with the write splice wbit(buffer, pos, 0); - for(int sector = 0; sector != 16; sector ++) { + for(int sector = 0; sector != 16; sector++) { uint8_t sid = sector_map[sector]; for(int i=0; i != 7; i++) wbyte(buffer, pos, 0x80); @@ -69,7 +70,7 @@ void vtech_common_format::image_to_flux(const std::vector<uint8_t> &bdata, flopp wbyte(buffer, pos, 0xe7); wbyte(buffer, pos, 0xfe); uint16_t chk = 0; - const uint8_t *src = bdata.data() + 16*128*track + 128*sid; + const uint8_t *src = &bdata[16*128*track + 128*sid]; for(int i=0; i != 128; i++) { chk += src[i]; wbyte(buffer, pos, src[i]); @@ -106,7 +107,7 @@ std::vector<uint8_t> vtech_common_format::flux_to_image(const floppy_image &imag for(;;) { int npos = cpos; for(;;) { - npos ++; + npos++; if(npos == sz) npos = 0; if((buffer[npos] & floppy_image::MG_MASK) == floppy_image::MG_F) @@ -115,7 +116,11 @@ std::vector<uint8_t> vtech_common_format::flux_to_image(const floppy_image &imag int dt = (buffer[npos] & floppy_image::TIME_MASK) - (buffer[cpos] & floppy_image::TIME_MASK); if(dt < 0) cpos += 200000000; - bitstream.push_back(dt < 9187 - 143); + int t = dt >= 9187 - 143 ? 0 : + dt >= 2237 - 143 && dt <= 2237 + 143 ? 1 : + 2; + if(t <= 1) + bitstream.push_back(t); if(npos <= cpos) break; cpos = npos; @@ -135,7 +140,7 @@ std::vector<uint8_t> vtech_common_format::flux_to_image(const floppy_image &imag buf = (buf << 1) | bitstream[sz-64+i]; for(;;) { buf = (buf << 1) | bitstream[pos]; - count ++; + count++; switch(mode) { case 0: // idle if(buf == 0x80808000fee718c3) @@ -219,7 +224,7 @@ const char *vtech_dsk_format::description() const noexcept const char *vtech_dsk_format::extensions() const noexcept { - return "dsk"; + return "dsk,dvz"; } int vtech_bin_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const @@ -243,15 +248,15 @@ int vtech_dsk_format::identify(util::random_read &io, uint32_t form_factor, cons if(size < 256) return 0; - std::vector<uint8_t> bdata(size); - size_t actual; - io.read_at(0, bdata.data(), size, actual); + auto const [err, bdata, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return 0; // Structurally validate the presence of sector headers and data int count_sh = 0, count_sd = 0; uint64_t buf = 0; - for(uint8_t b : bdata) { - buf = (buf << 8) | b; + for(size_t i = 0; size > i; ++i) { + buf = (buf << 8) | bdata[i]; if(buf == 0x80808000fee718c3) count_sh++; else if(buf == 0x80808000c318e7fe) @@ -267,11 +272,11 @@ bool vtech_bin_format::load(util::random_read &io, uint32_t form_factor, const s if(io.length(size) || (size != 40*16*256)) return false; - std::vector<uint8_t> bdata(size); - size_t actual; - io.read_at(0, bdata.data(), size, actual); + auto const [err, bdata, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return false; - image_to_flux(bdata, image); + image_to_flux(bdata.get(), size, image); image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); return true; } @@ -281,9 +286,9 @@ bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const s uint64_t size; if(io.length(size)) return false; - std::vector<uint8_t> bdata(size); - size_t actual; - io.read_at(0, bdata.data(), size, actual); + auto const [err, bdata, actual] = read_at(io, 0, size); + if(err || (actual != size)) + return false; std::vector<uint8_t> bdatax(128*16*40, 0); @@ -293,9 +298,9 @@ bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const s uint64_t buf = 0; uint8_t *dest = nullptr; - for(uint8_t b : bdata) { - buf = (buf << 8) | b; - count ++; + for(size_t i = 0; size > i; ++i) { + buf = (buf << 8) | bdata[i]; + count++; switch(mode) { case 0: // idle if(buf == 0x80808000fee718c3) @@ -305,14 +310,14 @@ bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const s case 1: // sector header if(count == 3) { - uint8_t trk = buf >> 16; - uint8_t sector = buf >> 8; - uint8_t chk = buf; + const uint8_t trk = buf >> 16; + const uint8_t sector = buf >> 8; + const uint8_t chk = buf; if(chk != sector + trk) { mode = 0; break; } - dest = bdatax.data() + 128*16*trk + sector*128; + dest = &bdatax[128*16*trk + sector*128]; checksum = 0; mode = 2; } @@ -328,7 +333,7 @@ bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const s case 3: // sector data if(count <= 128) { - uint8_t byte = buf; + const uint8_t byte = buf; checksum += byte; *dest++ = byte; @@ -341,7 +346,7 @@ bool vtech_dsk_format::load(util::random_read &io, uint32_t form_factor, const s } } - image_to_flux(bdatax, image); + image_to_flux(bdatax.data(), bdatax.size(), image); image.set_form_variant(floppy_image::FF_525, floppy_image::SSSD); return true; } @@ -354,8 +359,7 @@ bool vtech_bin_format::save(util::random_read_write &io, const std::vector<uint3 return false; auto bdata = flux_to_image(image); - size_t actual; - io.write_at(0, bdata.data(), bdata.size(), actual); + /*auto const [err, actual] =*/ write_at(io, 0, bdata.data(), bdata.size()); // FIXME: check for errors return true; } @@ -376,8 +380,8 @@ bool vtech_dsk_format::save(util::random_read_write &io, const std::vector<uint3 }; int pos = 0; - for(int track = 0; track != 40; track ++) { - for(int sector = 0; sector != 16; sector ++) { + for(int track = 0; track != 40; track++) { + for(int sector = 0; sector != 16; sector++) { uint8_t sid = sector_map[sector]; for(int i=0; i != 7; i++) bdatax[pos++] = 0x80; @@ -407,8 +411,7 @@ bool vtech_dsk_format::save(util::random_read_write &io, const std::vector<uint3 } } - size_t actual; - io.write_at(0, bdatax.data(), bdatax.size(), actual); + /*auto const [err, actual] =*/ write_at(io, 0, bdatax.data(), bdatax.size()); // FIXME: check for errors return true; } diff --git a/src/lib/formats/vt_dsk.h b/src/lib/formats/vt_dsk.h index db2687d4108..1348f9dbd4d 100644 --- a/src/lib/formats/vt_dsk.h +++ b/src/lib/formats/vt_dsk.h @@ -19,7 +19,7 @@ public: virtual bool supports_save() const noexcept override { return true; } protected: - static void image_to_flux(const std::vector<uint8_t> &bdata, floppy_image &image); + static void image_to_flux(const uint8_t *bdata, size_t size, floppy_image &image); static std::vector<uint8_t> flux_to_image(const floppy_image &image); static void wbit(std::vector<uint32_t> &buffer, uint32_t &pos, bool bit); diff --git a/src/lib/formats/wavfile.cpp b/src/lib/formats/wavfile.cpp index e410c7f9ff9..6cce494f1c8 100644 --- a/src/lib/formats/wavfile.cpp +++ b/src/lib/formats/wavfile.cpp @@ -170,7 +170,6 @@ static cassette_image::error wavfile_identify(cassette_image *cassette, cassette static cassette_image::error wavfile_load(cassette_image *cassette) { cassette_image::Options opts; - memset(&opts, 0, sizeof(opts)); return wavfile_process(cassette, &opts, true); } diff --git a/src/lib/formats/wd177x_dsk.cpp b/src/lib/formats/wd177x_dsk.cpp index c3bba8f7724..e5b02f02e32 100644 --- a/src/lib/formats/wd177x_dsk.cpp +++ b/src/lib/formats/wd177x_dsk.cpp @@ -262,8 +262,7 @@ bool wd177x_format::load(util::random_read &io, uint32_t form_factor, const std: build_sector_description(tf, sectdata, sectors, track, head); int track_size = compute_track_size(tf); - size_t actual; - io.read_at(get_image_offset(f, head, track), sectdata, track_size, actual); + /*auto const [err, actual] =*/ read_at(io, get_image_offset(f, head, track), sectdata, track_size); // FIXME: check for errors and premature EOF generate_track(desc, track, head, sectors, tf.sector_count, total_size, image); } @@ -389,8 +388,7 @@ bool wd177x_format::save(util::random_read_write &io, const std::vector<uint32_t build_sector_description(tf, sectdata, sectors, track, head); extract_sectors(image, tf, sectors, track, head); int track_size = compute_track_size(tf); - size_t actual; - io.write_at(get_image_offset(f, head, track), sectdata, track_size, actual); + /*auto const [err, actual] =*/ write_at(io, get_image_offset(f, head, track), sectdata, track_size); // FIXME: check for errors } } diff --git a/src/lib/formats/x07_cas.cpp b/src/lib/formats/x07_cas.cpp index 71e8b304efc..945e1ee5c1a 100644 --- a/src/lib/formats/x07_cas.cpp +++ b/src/lib/formats/x07_cas.cpp @@ -122,7 +122,7 @@ static int x07_handle_cassette(int16_t *buffer, const uint8_t *bytes) Generate samples for the tape image ********************************************************************/ -static int x07_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int x07_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { return x07_handle_cassette(buffer, bytes); } diff --git a/src/lib/formats/x1_tap.cpp b/src/lib/formats/x1_tap.cpp index 1a60bb18330..f730fe9fb21 100644 --- a/src/lib/formats/x1_tap.cpp +++ b/src/lib/formats/x1_tap.cpp @@ -101,7 +101,7 @@ static int x1_cas_to_wav_size (const uint8_t *casdata, int caslen) /******************************************************************* Generate samples for the tape image ********************************************************************/ -static int x1_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes) +static int x1_cas_fill_wave(int16_t *buffer, int sample_count, const uint8_t *bytes, int) { return x1_handle_tap(buffer,bytes); } diff --git a/src/lib/formats/zx81_p.cpp b/src/lib/formats/zx81_p.cpp index e31b5f58933..515f5b78581 100644 --- a/src/lib/formats/zx81_p.cpp +++ b/src/lib/formats/zx81_p.cpp @@ -173,7 +173,7 @@ static int zx81_cassette_calculate_size_in_samples(const uint8_t *bytes, int len return (number_of_0_data+number_of_0_name)*ZX81_LOW_BIT_LENGTH + (number_of_1_data+number_of_1_name)*ZX81_HIGH_BIT_LENGTH + ZX81_PILOT_LENGTH; } -static int zx81_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int zx81_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { int16_t * p = buffer; int i; @@ -250,7 +250,7 @@ static int zx80_cassette_calculate_size_in_samples(const uint8_t *bytes, int len return number_of_0_data*ZX81_LOW_BIT_LENGTH + number_of_1_data*ZX81_HIGH_BIT_LENGTH + ZX81_PILOT_LENGTH; } -static int zx80_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes) +static int zx80_cassette_fill_wave(int16_t *buffer, int length, const uint8_t *bytes, int) { int16_t * p = buffer; int i; diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index 077b72b028f..2a63e816c0a 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -146,13 +146,12 @@ OBJDIRS = $(OBJ) \ $(OBJ)/solver \ $(OBJ)/devices \ $(OBJ)/plib \ - $(OBJ)/devices \ $(OBJ)/macro \ $(OBJ)/macro/modules \ $(OBJ)/tests \ $(OBJ)/tools \ $(OBJ)/prg \ - $(OBJ)/generated \ + $(OBJ)/generated MODULESOURCES += $(wildcard $(SRC)/macro/modules/*.cpp) DEVSOURCES = $(SRC)/solver/nld_solver.cpp @@ -171,7 +170,7 @@ CORESOURCES := \ $(SRC)/nl_setup.cpp \ $(SRC)/nl_factory.cpp \ $(SRC)/tools/nl_convert.cpp \ - $(SRC)/generated/static_solvers.cpp \ + $(SRC)/generated/static_solvers.cpp MAINSOURCES = $(SRC)/prg/nltool.cpp $(SRC)/prg/nlwav.cpp @@ -196,7 +195,7 @@ PSOURCES := \ $(PSRC)/ppmf.cpp \ $(PSRC)/ppreprocessor.cpp \ $(PSRC)/ptokenizer.cpp \ - $(PSRC)/putil.cpp \ + $(PSRC)/putil.cpp NLOBJS = $(patsubst $(SRC)%, $(OBJ)%, $(CORESOURCES:.cpp=.o)) NLDEVOBJS = $(patsubst $(SRC)%, $(OBJ)%, $(DEVSOURCES:.cpp=.o)) @@ -213,7 +212,7 @@ VSFILES = \ $(VSBUILD)/nltool.vcxproj.filters \ $(VSBUILD)/nlwav.vcxproj \ $(VSBUILD)/nlwav.vcxproj.filters \ - $(VSBUILD)/netlist.sln \ + $(VSBUILD)/netlist.sln OTHERFILES = makefile @@ -223,7 +222,7 @@ DOCS = \ $(DOC)/mainpage.dox.h \ $(DOC)/primer_1.dox.h \ $(DOC)/structure.dox.h \ - $(DOC)/test1-50r.svg \ + $(DOC)/test1-50r.svg ALL_OBJS = $(OBJS) $(MAINOBJS) diff --git a/src/lib/netlist/generated/static_solvers.cpp b/src/lib/netlist/generated/static_solvers.cpp index ff615be2670..8f01960ce72 100644 --- a/src/lib/netlist/generated/static_solvers.cpp +++ b/src/lib/netlist/generated/static_solvers.cpp @@ -542,2340 +542,6 @@ static void nl_gcr_90_double_double_ce766957cb26ff3e(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// 280zzzap,sspeedr -static void nl_gcr_113_double_double_ab9144d965a37e4(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - double m_A13(0.0); - double m_A14(0.0); - double m_A15(0.0); - double m_A16(0.0); - double m_A17(0.0); - double m_A18(0.0); - double m_A19(0.0); - double m_A20(0.0); - double m_A21(0.0); - double m_A22(0.0); - double m_A23(0.0); - double m_A24(0.0); - double m_A25(0.0); - double m_A26(0.0); - double m_A27(0.0); - double m_A28(0.0); - double m_A29(0.0); - double m_A30(0.0); - double m_A31(0.0); - double m_A32(0.0); - double m_A33(0.0); - double m_A34(0.0); - double m_A35(0.0); - double m_A36(0.0); - double m_A37(0.0); - double m_A38(0.0); - double m_A39(0.0); - double m_A40(0.0); - double m_A41(0.0); - double m_A42(0.0); - double m_A43(0.0); - double m_A44(0.0); - double m_A45(0.0); - double m_A46(0.0); - double m_A47(0.0); - double m_A48(0.0); - double m_A49(0.0); - double m_A50(0.0); - double m_A51(0.0); - double m_A52(0.0); - double m_A53(0.0); - double m_A54(0.0); - double m_A55(0.0); - double m_A56(0.0); - double m_A57(0.0); - double m_A58(0.0); - double m_A59(0.0); - double m_A60(0.0); - double m_A61(0.0); - double m_A62(0.0); - double m_A63(0.0); - double m_A64(0.0); - double m_A65(0.0); - double m_A66(0.0); - double m_A67(0.0); - double m_A68(0.0); - double m_A69(0.0); - double m_A70(0.0); - double m_A71(0.0); - double m_A72(0.0); - double m_A73(0.0); - double m_A74(0.0); - double m_A75(0.0); - double m_A76(0.0); - double m_A77(0.0); - double m_A78(0.0); - double m_A79(0.0); - double m_A80(0.0); - double m_A81(0.0); - double m_A82(0.0); - double m_A83(0.0); - double m_A84(0.0); - double m_A85(0.0); - double m_A86(0.0); - double m_A87(0.0); - double m_A88(0.0); - double m_A89(0.0); - double m_A90(0.0); - double m_A91(0.0); - double m_A92(0.0); - double m_A93(0.0); - double m_A94(0.0); - double m_A95(0.0); - double m_A96(0.0); - double m_A97(0.0); - double m_A98(0.0); - double m_A99(0.0); - double m_A100(0.0); - double m_A101(0.0); - double m_A102(0.0); - double m_A103(0.0); - double m_A104(0.0); - double m_A105(0.0); - double m_A106(0.0); - double m_A107(0.0); - double m_A108(0.0); - double m_A109(0.0); - double m_A110(0.0); - double m_A111(0.0); - double m_A112(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A2 += gt[5]; - m_A5 += go[2]; - m_A4 += go[3]; - m_A3 += go[4]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 += Idr[4]; - RHS1 += Idr[5]; - RHS1 -= go[5] * *cnV[5]; - m_A6 += gt[6]; - m_A6 += gt[7]; - m_A7 += go[6]; - double RHS2 = Idr[6]; - RHS2 += Idr[7]; - RHS2 -= go[7] * *cnV[7]; - m_A8 += gt[8]; - m_A8 += gt[9]; - m_A9 += go[8]; - double RHS3 = Idr[8]; - RHS3 += Idr[9]; - RHS3 -= go[9] * *cnV[9]; - m_A10 += gt[10]; - m_A10 += gt[11]; - m_A10 += gt[12]; - m_A11 += go[10]; - m_A12 += go[11]; - double RHS4 = Idr[10]; - RHS4 += Idr[11]; - RHS4 += Idr[12]; - RHS4 -= go[12] * *cnV[12]; - m_A13 += gt[13]; - m_A13 += gt[14]; - m_A14 += go[13]; - double RHS5 = Idr[13]; - RHS5 += Idr[14]; - RHS5 -= go[14] * *cnV[14]; - m_A15 += gt[15]; - m_A15 += gt[16]; - m_A15 += gt[17]; - m_A15 += gt[18]; - m_A15 += gt[19]; - m_A15 += gt[20]; - m_A15 += gt[21]; - m_A18 += go[15]; - m_A19 += go[16]; - m_A17 += go[17]; - m_A16 += go[18]; - double RHS6 = Idr[15]; - RHS6 += Idr[16]; - RHS6 += Idr[17]; - RHS6 += Idr[18]; - RHS6 += Idr[19]; - RHS6 += Idr[20]; - RHS6 += Idr[21]; - RHS6 -= go[19] * *cnV[19]; - RHS6 -= go[20] * *cnV[20]; - RHS6 -= go[21] * *cnV[21]; - m_A20 += gt[22]; - m_A20 += gt[23]; - m_A20 += gt[24]; - m_A20 += gt[25]; - m_A20 += gt[26]; - m_A20 += gt[27]; - m_A20 += gt[28]; - m_A23 += go[22]; - m_A24 += go[23]; - m_A22 += go[24]; - m_A21 += go[25]; - double RHS7 = Idr[22]; - RHS7 += Idr[23]; - RHS7 += Idr[24]; - RHS7 += Idr[25]; - RHS7 += Idr[26]; - RHS7 += Idr[27]; - RHS7 += Idr[28]; - RHS7 -= go[26] * *cnV[26]; - RHS7 -= go[27] * *cnV[27]; - RHS7 -= go[28] * *cnV[28]; - m_A25 += gt[29]; - m_A25 += gt[30]; - m_A25 += gt[31]; - m_A26 += go[29]; - m_A27 += go[30]; - double RHS8 = Idr[29]; - RHS8 += Idr[30]; - RHS8 += Idr[31]; - RHS8 -= go[31] * *cnV[31]; - m_A28 += gt[32]; - m_A28 += gt[33]; - m_A29 += go[32]; - double RHS9 = Idr[32]; - RHS9 += Idr[33]; - RHS9 -= go[33] * *cnV[33]; - m_A30 += gt[34]; - m_A30 += gt[35]; - m_A30 += gt[36]; - m_A30 += gt[37]; - m_A31 += go[34]; - double RHS10 = Idr[34]; - RHS10 += Idr[35]; - RHS10 += Idr[36]; - RHS10 += Idr[37]; - RHS10 -= go[35] * *cnV[35]; - RHS10 -= go[36] * *cnV[36]; - RHS10 -= go[37] * *cnV[37]; - m_A32 += gt[38]; - m_A32 += gt[39]; - m_A33 += go[38]; - double RHS11 = Idr[38]; - RHS11 += Idr[39]; - RHS11 -= go[39] * *cnV[39]; - m_A36 += gt[40]; - m_A36 += gt[41]; - m_A36 += gt[42]; - m_A36 += gt[43]; - m_A35 += go[40]; - m_A34 += go[41]; - double RHS12 = Idr[40]; - RHS12 += Idr[41]; - RHS12 += Idr[42]; - RHS12 += Idr[43]; - RHS12 -= go[42] * *cnV[42]; - RHS12 -= go[43] * *cnV[43]; - m_A42 += gt[44]; - m_A42 += gt[45]; - m_A42 += gt[46]; - m_A42 += gt[47]; - m_A40 += go[44]; - m_A39 += go[45]; - double RHS13 = Idr[44]; - RHS13 += Idr[45]; - RHS13 += Idr[46]; - RHS13 += Idr[47]; - RHS13 -= go[46] * *cnV[46]; - RHS13 -= go[47] * *cnV[47]; - m_A51 += gt[48]; - m_A51 += gt[49]; - m_A51 += gt[50]; - m_A51 += gt[51]; - m_A53 += go[48]; - m_A48 += go[49]; - m_A47 += go[50]; - double RHS14 = Idr[48]; - RHS14 += Idr[49]; - RHS14 += Idr[50]; - RHS14 += Idr[51]; - RHS14 -= go[51] * *cnV[51]; - m_A57 += gt[52]; - m_A57 += gt[53]; - m_A57 += gt[54]; - m_A56 += go[52]; - m_A58 += go[53]; - double RHS15 = Idr[52]; - RHS15 += Idr[53]; - RHS15 += Idr[54]; - RHS15 -= go[54] * *cnV[54]; - m_A60 += gt[55]; - m_A60 += gt[56]; - m_A60 += gt[57]; - m_A60 += gt[58]; - m_A59 += go[55]; - m_A61 += go[56]; - double RHS16 = Idr[55]; - RHS16 += Idr[56]; - RHS16 += Idr[57]; - RHS16 += Idr[58]; - RHS16 -= go[57] * *cnV[57]; - RHS16 -= go[58] * *cnV[58]; - m_A67 += gt[59]; - m_A67 += gt[60]; - m_A67 += gt[61]; - m_A67 += gt[62]; - m_A67 += gt[63]; - m_A67 += gt[64]; - m_A70 += go[59]; - m_A64 += go[60]; - m_A63 += go[61]; - m_A62 += go[62]; - m_A69 += go[63]; - double RHS17 = Idr[59]; - RHS17 += Idr[60]; - RHS17 += Idr[61]; - RHS17 += Idr[62]; - RHS17 += Idr[63]; - RHS17 += Idr[64]; - RHS17 -= go[64] * *cnV[64]; - m_A74 += gt[65]; - m_A74 += gt[66]; - m_A74 += gt[67]; - m_A74 += gt[68]; - m_A73 += go[65]; - m_A72 += go[66]; - m_A75 += go[67]; - double RHS18 = Idr[65]; - RHS18 += Idr[66]; - RHS18 += Idr[67]; - RHS18 += Idr[68]; - RHS18 -= go[68] * *cnV[68]; - m_A80 += gt[69]; - m_A80 += gt[70]; - m_A80 += gt[71]; - m_A80 += gt[72]; - m_A80 += gt[73]; - m_A77 += go[69]; - m_A78 += go[70]; - m_A76 += go[71]; - double RHS19 = Idr[69]; - RHS19 += Idr[70]; - RHS19 += Idr[71]; - RHS19 += Idr[72]; - RHS19 += Idr[73]; - RHS19 -= go[72] * *cnV[72]; - RHS19 -= go[73] * *cnV[73]; - m_A89 += gt[74]; - m_A89 += gt[75]; - m_A89 += gt[76]; - m_A89 += gt[77]; - m_A84 += go[74]; - m_A85 += go[75]; - m_A87 += go[76]; - m_A86 += go[77]; - double RHS20 = Idr[74]; - RHS20 += Idr[75]; - RHS20 += Idr[76]; - RHS20 += Idr[77]; - m_A100 += gt[78]; - m_A100 += gt[79]; - m_A100 += gt[80]; - m_A100 += gt[81]; - m_A100 += gt[82]; - m_A100 += gt[83]; - m_A100 += gt[84]; - m_A96 += go[78]; - m_A93 += go[79]; - m_A101 += go[80]; - m_A92 += go[81]; - m_A97 += go[82]; - double RHS21 = Idr[78]; - RHS21 += Idr[79]; - RHS21 += Idr[80]; - RHS21 += Idr[81]; - RHS21 += Idr[82]; - RHS21 += Idr[83]; - RHS21 += Idr[84]; - RHS21 -= go[83] * *cnV[83]; - RHS21 -= go[84] * *cnV[84]; - m_A112 += gt[85]; - m_A112 += gt[86]; - m_A112 += gt[87]; - m_A112 += gt[88]; - m_A112 += gt[89]; - m_A112 += gt[90]; - m_A108 += go[85]; - m_A111 += go[86]; - m_A103 += go[87]; - m_A104 += go[88]; - m_A102 += go[89]; - double RHS22 = Idr[85]; - RHS22 += Idr[86]; - RHS22 += Idr[87]; - RHS22 += Idr[88]; - RHS22 += Idr[89]; - RHS22 += Idr[90]; - RHS22 -= go[90] * *cnV[90]; - const double f0 = 1.0 / m_A0; - const double f0_12 = -f0 * m_A34; - m_A36 += m_A1 * f0_12; - RHS12 += f0_12 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_12 = -f1 * m_A35; - m_A36 += m_A3 * f1_12; - m_A37 += m_A4 * f1_12; - m_A38 += m_A5 * f1_12; - RHS12 += f1_12 * RHS1; - const double f1_13 = -f1 * m_A39; - m_A41 += m_A3 * f1_13; - m_A42 += m_A4 * f1_13; - m_A43 += m_A5 * f1_13; - RHS13 += f1_13 * RHS1; - const double f1_14 = -f1 * m_A47; - m_A49 += m_A3 * f1_14; - m_A50 += m_A4 * f1_14; - m_A51 += m_A5 * f1_14; - RHS14 += f1_14 * RHS1; - const double f2 = 1.0 / m_A6; - const double f2_15 = -f2 * m_A56; - m_A57 += m_A7 * f2_15; - RHS15 += f2_15 * RHS2; - const double f3 = 1.0 / m_A8; - const double f3_20 = -f3 * m_A84; - m_A89 += m_A9 * f3_20; - RHS20 += f3_20 * RHS3; - const double f4 = 1.0 / m_A10; - const double f4_17 = -f4 * m_A62; - m_A67 += m_A11 * f4_17; - m_A69 += m_A12 * f4_17; - RHS17 += f4_17 * RHS4; - const double f4_20 = -f4 * m_A85; - m_A87 += m_A11 * f4_20; - m_A89 += m_A12 * f4_20; - RHS20 += f4_20 * RHS4; - const double f5 = 1.0 / m_A13; - const double f5_16 = -f5 * m_A59; - m_A60 += m_A14 * f5_16; - RHS16 += f5_16 * RHS5; - const double f6 = 1.0 / m_A15; - const double f6_13 = -f6 * m_A40; - m_A42 += m_A16 * f6_13; - m_A44 += m_A17 * f6_13; - m_A45 += m_A18 * f6_13; - m_A46 += m_A19 * f6_13; - RHS13 += f6_13 * RHS6; - const double f6_17 = -f6 * m_A63; - m_A65 += m_A16 * f6_17; - m_A67 += m_A17 * f6_17; - m_A70 += m_A18 * f6_17; - m_A71 += m_A19 * f6_17; - RHS17 += f6_17 * RHS6; - const double f6_21 = -f6 * m_A92; - m_A94 += m_A16 * f6_21; - m_A97 += m_A17 * f6_21; - m_A100 += m_A18 * f6_21; - m_A101 += m_A19 * f6_21; - RHS21 += f6_21 * RHS6; - const double f6_22 = -f6 * m_A102; - m_A105 += m_A16 * f6_22; - m_A107 += m_A17 * f6_22; - m_A111 += m_A18 * f6_22; - m_A112 += m_A19 * f6_22; - RHS22 += f6_22 * RHS6; - const double f7 = 1.0 / m_A20; - const double f7_14 = -f7 * m_A48; - m_A51 += m_A21 * f7_14; - m_A52 += m_A22 * f7_14; - m_A54 += m_A23 * f7_14; - m_A55 += m_A24 * f7_14; - RHS14 += f7_14 * RHS7; - const double f7_17 = -f7 * m_A64; - m_A66 += m_A21 * f7_17; - m_A67 += m_A22 * f7_17; - m_A70 += m_A23 * f7_17; - m_A71 += m_A24 * f7_17; - RHS17 += f7_17 * RHS7; - const double f7_21 = -f7 * m_A93; - m_A95 += m_A21 * f7_21; - m_A97 += m_A22 * f7_21; - m_A100 += m_A23 * f7_21; - m_A101 += m_A24 * f7_21; - RHS21 += f7_21 * RHS7; - const double f7_22 = -f7 * m_A103; - m_A106 += m_A21 * f7_22; - m_A107 += m_A22 * f7_22; - m_A111 += m_A23 * f7_22; - m_A112 += m_A24 * f7_22; - RHS22 += f7_22 * RHS7; - const double f8 = 1.0 / m_A25; - const double f8_18 = -f8 * m_A72; - m_A74 += m_A26 * f8_18; - m_A75 += m_A27 * f8_18; - RHS18 += f8_18 * RHS8; - const double f8_22 = -f8 * m_A104; - m_A108 += m_A26 * f8_22; - m_A112 += m_A27 * f8_22; - RHS22 += f8_22 * RHS8; - const double f9 = 1.0 / m_A28; - const double f9_18 = -f9 * m_A73; - m_A74 += m_A29 * f9_18; - RHS18 += f9_18 * RHS9; - const double f10 = 1.0 / m_A30; - const double f10_19 = -f10 * m_A76; - m_A80 += m_A31 * f10_19; - RHS19 += f10_19 * RHS10; - const double f11 = 1.0 / m_A32; - const double f11_19 = -f11 * m_A77; - m_A80 += m_A33 * f11_19; - RHS19 += f11_19 * RHS11; - const double f12 = 1.0 / m_A36; - const double f12_13 = -f12 * m_A41; - m_A42 += m_A37 * f12_13; - m_A43 += m_A38 * f12_13; - RHS13 += f12_13 * RHS12; - const double f12_14 = -f12 * m_A49; - m_A50 += m_A37 * f12_14; - m_A51 += m_A38 * f12_14; - RHS14 += f12_14 * RHS12; - const double f13 = 1.0 / m_A42; - const double f13_14 = -f13 * m_A50; - m_A51 += m_A43 * f13_14; - m_A52 += m_A44 * f13_14; - m_A54 += m_A45 * f13_14; - m_A55 += m_A46 * f13_14; - RHS14 += f13_14 * RHS13; - const double f13_17 = -f13 * m_A65; - m_A66 += m_A43 * f13_17; - m_A67 += m_A44 * f13_17; - m_A70 += m_A45 * f13_17; - m_A71 += m_A46 * f13_17; - RHS17 += f13_17 * RHS13; - const double f13_21 = -f13 * m_A94; - m_A95 += m_A43 * f13_21; - m_A97 += m_A44 * f13_21; - m_A100 += m_A45 * f13_21; - m_A101 += m_A46 * f13_21; - RHS21 += f13_21 * RHS13; - const double f13_22 = -f13 * m_A105; - m_A106 += m_A43 * f13_22; - m_A107 += m_A44 * f13_22; - m_A111 += m_A45 * f13_22; - m_A112 += m_A46 * f13_22; - RHS22 += f13_22 * RHS13; - const double f14 = 1.0 / m_A51; - const double f14_17 = -f14 * m_A66; - m_A67 += m_A52 * f14_17; - m_A68 += m_A53 * f14_17; - m_A70 += m_A54 * f14_17; - m_A71 += m_A55 * f14_17; - RHS17 += f14_17 * RHS14; - const double f14_19 = -f14 * m_A78; - m_A79 += m_A52 * f14_19; - m_A80 += m_A53 * f14_19; - m_A82 += m_A54 * f14_19; - m_A83 += m_A55 * f14_19; - RHS19 += f14_19 * RHS14; - const double f14_21 = -f14 * m_A95; - m_A97 += m_A52 * f14_21; - m_A98 += m_A53 * f14_21; - m_A100 += m_A54 * f14_21; - m_A101 += m_A55 * f14_21; - RHS21 += f14_21 * RHS14; - const double f14_22 = -f14 * m_A106; - m_A107 += m_A52 * f14_22; - m_A109 += m_A53 * f14_22; - m_A111 += m_A54 * f14_22; - m_A112 += m_A55 * f14_22; - RHS22 += f14_22 * RHS14; - const double f15 = 1.0 / m_A57; - const double f15_20 = -f15 * m_A86; - m_A89 += m_A58 * f15_20; - RHS20 += f15_20 * RHS15; - const double f16 = 1.0 / m_A60; - const double f16_21 = -f16 * m_A96; - m_A100 += m_A61 * f16_21; - RHS21 += f16_21 * RHS16; - const double f17 = 1.0 / m_A67; - const double f17_19 = -f17 * m_A79; - m_A80 += m_A68 * f17_19; - m_A81 += m_A69 * f17_19; - m_A82 += m_A70 * f17_19; - m_A83 += m_A71 * f17_19; - RHS19 += f17_19 * RHS17; - const double f17_20 = -f17 * m_A87; - m_A88 += m_A68 * f17_20; - m_A89 += m_A69 * f17_20; - m_A90 += m_A70 * f17_20; - m_A91 += m_A71 * f17_20; - RHS20 += f17_20 * RHS17; - const double f17_21 = -f17 * m_A97; - m_A98 += m_A68 * f17_21; - m_A99 += m_A69 * f17_21; - m_A100 += m_A70 * f17_21; - m_A101 += m_A71 * f17_21; - RHS21 += f17_21 * RHS17; - const double f17_22 = -f17 * m_A107; - m_A109 += m_A68 * f17_22; - m_A110 += m_A69 * f17_22; - m_A111 += m_A70 * f17_22; - m_A112 += m_A71 * f17_22; - RHS22 += f17_22 * RHS17; - const double f18 = 1.0 / m_A74; - const double f18_22 = -f18 * m_A108; - m_A112 += m_A75 * f18_22; - RHS22 += f18_22 * RHS18; - const double f19 = 1.0 / m_A80; - const double f19_20 = -f19 * m_A88; - m_A89 += m_A81 * f19_20; - m_A90 += m_A82 * f19_20; - m_A91 += m_A83 * f19_20; - RHS20 += f19_20 * RHS19; - const double f19_21 = -f19 * m_A98; - m_A99 += m_A81 * f19_21; - m_A100 += m_A82 * f19_21; - m_A101 += m_A83 * f19_21; - RHS21 += f19_21 * RHS19; - const double f19_22 = -f19 * m_A109; - m_A110 += m_A81 * f19_22; - m_A111 += m_A82 * f19_22; - m_A112 += m_A83 * f19_22; - RHS22 += f19_22 * RHS19; - const double f20 = 1.0 / m_A89; - const double f20_21 = -f20 * m_A99; - m_A100 += m_A90 * f20_21; - m_A101 += m_A91 * f20_21; - RHS21 += f20_21 * RHS20; - const double f20_22 = -f20 * m_A110; - m_A111 += m_A90 * f20_22; - m_A112 += m_A91 * f20_22; - RHS22 += f20_22 * RHS20; - const double f21 = 1.0 / m_A100; - const double f21_22 = -f21 * m_A111; - m_A112 += m_A101 * f21_22; - RHS22 += f21_22 * RHS21; - V[22] = RHS22 / m_A112; - double tmp21 = 0.0; - tmp21 += m_A101 * V[22]; - V[21] = (RHS21 - tmp21) / m_A100; - double tmp20 = 0.0; - tmp20 += m_A90 * V[21]; - tmp20 += m_A91 * V[22]; - V[20] = (RHS20 - tmp20) / m_A89; - double tmp19 = 0.0; - tmp19 += m_A81 * V[20]; - tmp19 += m_A82 * V[21]; - tmp19 += m_A83 * V[22]; - V[19] = (RHS19 - tmp19) / m_A80; - double tmp18 = 0.0; - tmp18 += m_A75 * V[22]; - V[18] = (RHS18 - tmp18) / m_A74; - double tmp17 = 0.0; - tmp17 += m_A68 * V[19]; - tmp17 += m_A69 * V[20]; - tmp17 += m_A70 * V[21]; - tmp17 += m_A71 * V[22]; - V[17] = (RHS17 - tmp17) / m_A67; - double tmp16 = 0.0; - tmp16 += m_A61 * V[21]; - V[16] = (RHS16 - tmp16) / m_A60; - double tmp15 = 0.0; - tmp15 += m_A58 * V[20]; - V[15] = (RHS15 - tmp15) / m_A57; - double tmp14 = 0.0; - tmp14 += m_A52 * V[17]; - tmp14 += m_A53 * V[19]; - tmp14 += m_A54 * V[21]; - tmp14 += m_A55 * V[22]; - V[14] = (RHS14 - tmp14) / m_A51; - double tmp13 = 0.0; - tmp13 += m_A43 * V[14]; - tmp13 += m_A44 * V[17]; - tmp13 += m_A45 * V[21]; - tmp13 += m_A46 * V[22]; - V[13] = (RHS13 - tmp13) / m_A42; - double tmp12 = 0.0; - tmp12 += m_A37 * V[13]; - tmp12 += m_A38 * V[14]; - V[12] = (RHS12 - tmp12) / m_A36; - double tmp11 = 0.0; - tmp11 += m_A33 * V[19]; - V[11] = (RHS11 - tmp11) / m_A32; - double tmp10 = 0.0; - tmp10 += m_A31 * V[19]; - V[10] = (RHS10 - tmp10) / m_A30; - double tmp9 = 0.0; - tmp9 += m_A29 * V[18]; - V[9] = (RHS9 - tmp9) / m_A28; - double tmp8 = 0.0; - tmp8 += m_A26 * V[18]; - tmp8 += m_A27 * V[22]; - V[8] = (RHS8 - tmp8) / m_A25; - double tmp7 = 0.0; - tmp7 += m_A21 * V[14]; - tmp7 += m_A22 * V[17]; - tmp7 += m_A23 * V[21]; - tmp7 += m_A24 * V[22]; - V[7] = (RHS7 - tmp7) / m_A20; - double tmp6 = 0.0; - tmp6 += m_A16 * V[13]; - tmp6 += m_A17 * V[17]; - tmp6 += m_A18 * V[21]; - tmp6 += m_A19 * V[22]; - V[6] = (RHS6 - tmp6) / m_A15; - double tmp5 = 0.0; - tmp5 += m_A14 * V[16]; - V[5] = (RHS5 - tmp5) / m_A13; - double tmp4 = 0.0; - tmp4 += m_A11 * V[17]; - tmp4 += m_A12 * V[20]; - V[4] = (RHS4 - tmp4) / m_A10; - double tmp3 = 0.0; - tmp3 += m_A9 * V[20]; - V[3] = (RHS3 - tmp3) / m_A8; - double tmp2 = 0.0; - tmp2 += m_A7 * V[15]; - V[2] = (RHS2 - tmp2) / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[12]; - tmp1 += m_A4 * V[13]; - tmp1 += m_A5 * V[14]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[12]; - V[0] = (RHS0 - tmp0) / m_A0; -} - -// 280zzzap,sspeedr -static void nl_gcr_122_double_double_42c57d523cac30d0(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - double m_A13(0.0); - double m_A14(0.0); - double m_A15(0.0); - double m_A16(0.0); - double m_A17(0.0); - double m_A18(0.0); - double m_A19(0.0); - double m_A20(0.0); - double m_A21(0.0); - double m_A22(0.0); - double m_A23(0.0); - double m_A24(0.0); - double m_A25(0.0); - double m_A26(0.0); - double m_A27(0.0); - double m_A28(0.0); - double m_A29(0.0); - double m_A30(0.0); - double m_A31(0.0); - double m_A32(0.0); - double m_A33(0.0); - double m_A34(0.0); - double m_A35(0.0); - double m_A36(0.0); - double m_A37(0.0); - double m_A38(0.0); - double m_A39(0.0); - double m_A40(0.0); - double m_A41(0.0); - double m_A42(0.0); - double m_A43(0.0); - double m_A44(0.0); - double m_A45(0.0); - double m_A46(0.0); - double m_A47(0.0); - double m_A48(0.0); - double m_A49(0.0); - double m_A50(0.0); - double m_A51(0.0); - double m_A52(0.0); - double m_A53(0.0); - double m_A54(0.0); - double m_A55(0.0); - double m_A56(0.0); - double m_A57(0.0); - double m_A58(0.0); - double m_A59(0.0); - double m_A60(0.0); - double m_A61(0.0); - double m_A62(0.0); - double m_A63(0.0); - double m_A64(0.0); - double m_A65(0.0); - double m_A66(0.0); - double m_A67(0.0); - double m_A68(0.0); - double m_A69(0.0); - double m_A70(0.0); - double m_A71(0.0); - double m_A72(0.0); - double m_A73(0.0); - double m_A74(0.0); - double m_A75(0.0); - double m_A76(0.0); - double m_A77(0.0); - double m_A78(0.0); - double m_A79(0.0); - double m_A80(0.0); - double m_A81(0.0); - double m_A82(0.0); - double m_A83(0.0); - double m_A84(0.0); - double m_A85(0.0); - double m_A86(0.0); - double m_A87(0.0); - double m_A88(0.0); - double m_A89(0.0); - double m_A90(0.0); - double m_A91(0.0); - double m_A92(0.0); - double m_A93(0.0); - double m_A94(0.0); - double m_A95(0.0); - double m_A96(0.0); - double m_A97(0.0); - double m_A98(0.0); - double m_A99(0.0); - double m_A100(0.0); - double m_A101(0.0); - double m_A102(0.0); - double m_A103(0.0); - double m_A104(0.0); - double m_A105(0.0); - double m_A106(0.0); - double m_A107(0.0); - double m_A108(0.0); - double m_A109(0.0); - double m_A110(0.0); - double m_A111(0.0); - double m_A112(0.0); - double m_A113(0.0); - double m_A114(0.0); - double m_A115(0.0); - double m_A116(0.0); - double m_A117(0.0); - double m_A118(0.0); - double m_A119(0.0); - double m_A120(0.0); - double m_A121(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A3 += go[2]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 -= go[3] * *cnV[3]; - m_A4 += gt[4]; - m_A4 += gt[5]; - m_A4 += gt[6]; - m_A5 += go[4]; - double RHS2 = Idr[4]; - RHS2 += Idr[5]; - RHS2 += Idr[6]; - RHS2 -= go[5] * *cnV[5]; - RHS2 -= go[6] * *cnV[6]; - m_A6 += gt[7]; - m_A6 += gt[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A6 += gt[11]; - m_A6 += gt[12]; - m_A6 += gt[13]; - m_A7 += go[7]; - double RHS3 = Idr[7]; - RHS3 += Idr[8]; - RHS3 += Idr[9]; - RHS3 += Idr[10]; - RHS3 += Idr[11]; - RHS3 += Idr[12]; - RHS3 += Idr[13]; - RHS3 -= go[8] * *cnV[8]; - RHS3 -= go[9] * *cnV[9]; - RHS3 -= go[10] * *cnV[10]; - RHS3 -= go[11] * *cnV[11]; - RHS3 -= go[12] * *cnV[12]; - RHS3 -= go[13] * *cnV[13]; - m_A8 += gt[14]; - m_A8 += gt[15]; - m_A9 += go[14]; - double RHS4 = Idr[14]; - RHS4 += Idr[15]; - RHS4 -= go[15] * *cnV[15]; - m_A10 += gt[16]; - m_A10 += gt[17]; - m_A10 += gt[18]; - m_A10 += gt[19]; - m_A12 += go[16]; - m_A13 += go[17]; - m_A11 += go[18]; - double RHS5 = Idr[16]; - RHS5 += Idr[17]; - RHS5 += Idr[18]; - RHS5 += Idr[19]; - RHS5 -= go[19] * *cnV[19]; - m_A14 += gt[20]; - m_A14 += gt[21]; - m_A14 += gt[22]; - m_A14 += gt[23]; - m_A14 += gt[24]; - m_A14 += gt[25]; - m_A14 += gt[26]; - m_A15 += go[20]; - double RHS6 = Idr[20]; - RHS6 += Idr[21]; - RHS6 += Idr[22]; - RHS6 += Idr[23]; - RHS6 += Idr[24]; - RHS6 += Idr[25]; - RHS6 += Idr[26]; - RHS6 -= go[21] * *cnV[21]; - RHS6 -= go[22] * *cnV[22]; - RHS6 -= go[23] * *cnV[23]; - RHS6 -= go[24] * *cnV[24]; - RHS6 -= go[25] * *cnV[25]; - RHS6 -= go[26] * *cnV[26]; - m_A16 += gt[27]; - m_A16 += gt[28]; - m_A18 += go[27]; - m_A17 += go[28]; - double RHS7 = Idr[27]; - RHS7 += Idr[28]; - m_A19 += gt[29]; - m_A19 += gt[30]; - m_A19 += gt[31]; - m_A20 += go[29]; - double RHS8 = Idr[29]; - RHS8 += Idr[30]; - RHS8 += Idr[31]; - RHS8 -= go[30] * *cnV[30]; - RHS8 -= go[31] * *cnV[31]; - m_A21 += gt[32]; - m_A21 += gt[33]; - m_A22 += go[32]; - double RHS9 = Idr[32]; - RHS9 += Idr[33]; - RHS9 -= go[33] * *cnV[33]; - m_A23 += gt[34]; - m_A23 += gt[35]; - m_A23 += gt[36]; - m_A24 += go[34]; - m_A25 += go[35]; - m_A25 += go[36]; - double RHS10 = Idr[34]; - RHS10 += Idr[35]; - RHS10 += Idr[36]; - m_A26 += gt[37]; - m_A26 += gt[38]; - m_A26 += gt[39]; - m_A26 += gt[40]; - m_A26 += gt[41]; - m_A26 += gt[42]; - m_A26 += gt[43]; - m_A27 += go[37]; - double RHS11 = Idr[37]; - RHS11 += Idr[38]; - RHS11 += Idr[39]; - RHS11 += Idr[40]; - RHS11 += Idr[41]; - RHS11 += Idr[42]; - RHS11 += Idr[43]; - RHS11 -= go[38] * *cnV[38]; - RHS11 -= go[39] * *cnV[39]; - RHS11 -= go[40] * *cnV[40]; - RHS11 -= go[41] * *cnV[41]; - RHS11 -= go[42] * *cnV[42]; - RHS11 -= go[43] * *cnV[43]; - m_A28 += gt[44]; - m_A28 += gt[45]; - m_A28 += gt[46]; - m_A29 += go[44]; - double RHS12 = Idr[44]; - RHS12 += Idr[45]; - RHS12 += Idr[46]; - RHS12 -= go[45] * *cnV[45]; - RHS12 -= go[46] * *cnV[46]; - m_A30 += gt[47]; - m_A30 += gt[48]; - m_A30 += gt[49]; - m_A30 += gt[50]; - m_A32 += go[47]; - m_A31 += go[48]; - m_A33 += go[49]; - double RHS13 = Idr[47]; - RHS13 += Idr[48]; - RHS13 += Idr[49]; - RHS13 += Idr[50]; - RHS13 -= go[50] * *cnV[50]; - m_A35 += gt[51]; - m_A35 += gt[52]; - m_A34 += go[51]; - double RHS14 = Idr[51]; - RHS14 += Idr[52]; - RHS14 -= go[52] * *cnV[52]; - m_A37 += gt[53]; - m_A37 += gt[54]; - m_A37 += gt[55]; - m_A37 += gt[56]; - m_A36 += go[53]; - m_A38 += go[54]; - double RHS15 = Idr[53]; - RHS15 += Idr[54]; - RHS15 += Idr[55]; - RHS15 += Idr[56]; - RHS15 -= go[55] * *cnV[55]; - RHS15 -= go[56] * *cnV[56]; - m_A40 += gt[57]; - m_A40 += gt[58]; - m_A39 += go[57]; - double RHS16 = Idr[57]; - RHS16 += Idr[58]; - RHS16 -= go[58] * *cnV[58]; - m_A43 += gt[59]; - m_A43 += gt[60]; - m_A41 += go[59]; - m_A42 += go[60]; - double RHS17 = Idr[59]; - RHS17 += Idr[60]; - m_A47 += gt[61]; - m_A47 += gt[62]; - m_A47 += gt[63]; - m_A47 += gt[64]; - m_A47 += gt[65]; - m_A46 += go[61]; - m_A49 += go[62]; - m_A50 += go[63]; - double RHS18 = Idr[61]; - RHS18 += Idr[62]; - RHS18 += Idr[63]; - RHS18 += Idr[64]; - RHS18 += Idr[65]; - RHS18 -= go[64] * *cnV[64]; - RHS18 -= go[65] * *cnV[65]; - m_A52 += gt[66]; - m_A52 += gt[67]; - m_A51 += go[66]; - double RHS19 = Idr[66]; - RHS19 += Idr[67]; - RHS19 -= go[67] * *cnV[67]; - m_A55 += gt[68]; - m_A55 += gt[69]; - m_A54 += go[68]; - m_A53 += go[69]; - double RHS20 = Idr[68]; - RHS20 += Idr[69]; - m_A60 += gt[70]; - m_A60 += gt[71]; - m_A60 += gt[72]; - m_A60 += gt[73]; - m_A59 += go[70]; - m_A61 += go[71]; - double RHS21 = Idr[70]; - RHS21 += Idr[71]; - RHS21 += Idr[72]; - RHS21 += Idr[73]; - RHS21 -= go[72] * *cnV[72]; - RHS21 -= go[73] * *cnV[73]; - m_A69 += gt[74]; - m_A69 += gt[75]; - m_A69 += gt[76]; - m_A69 += gt[77]; - m_A69 += gt[78]; - m_A69 += gt[79]; - m_A69 += gt[80]; - m_A69 += gt[81]; - m_A69 += gt[82]; - m_A62 += go[74]; - m_A65 += go[75]; - m_A65 += go[76]; - m_A64 += go[77]; - m_A63 += go[78]; - m_A71 += go[79]; - double RHS22 = Idr[74]; - RHS22 += Idr[75]; - RHS22 += Idr[76]; - RHS22 += Idr[77]; - RHS22 += Idr[78]; - RHS22 += Idr[79]; - RHS22 += Idr[80]; - RHS22 += Idr[81]; - RHS22 += Idr[82]; - RHS22 -= go[80] * *cnV[80]; - RHS22 -= go[81] * *cnV[81]; - RHS22 -= go[82] * *cnV[82]; - m_A75 += gt[83]; - m_A75 += gt[84]; - m_A75 += gt[85]; - m_A75 += gt[86]; - m_A74 += go[83]; - m_A76 += go[84]; - double RHS23 = Idr[83]; - RHS23 += Idr[84]; - RHS23 += Idr[85]; - RHS23 += Idr[86]; - RHS23 -= go[85] * *cnV[85]; - RHS23 -= go[86] * *cnV[86]; - m_A82 += gt[87]; - m_A82 += gt[88]; - m_A82 += gt[89]; - m_A82 += gt[90]; - m_A82 += gt[91]; - m_A82 += gt[92]; - m_A77 += go[87]; - m_A78 += go[88]; - m_A84 += go[89]; - double RHS24 = Idr[87]; - RHS24 += Idr[88]; - RHS24 += Idr[89]; - RHS24 += Idr[90]; - RHS24 += Idr[91]; - RHS24 += Idr[92]; - RHS24 -= go[90] * *cnV[90]; - RHS24 -= go[91] * *cnV[91]; - RHS24 -= go[92] * *cnV[92]; - m_A93 += gt[93]; - m_A93 += gt[94]; - m_A93 += gt[95]; - m_A93 += gt[96]; - m_A93 += gt[97]; - m_A91 += go[93]; - m_A89 += go[94]; - m_A88 += go[95]; - m_A87 += go[96]; - m_A86 += go[97]; - double RHS25 = Idr[93]; - RHS25 += Idr[94]; - RHS25 += Idr[95]; - RHS25 += Idr[96]; - RHS25 += Idr[97]; - m_A104 += gt[98]; - m_A104 += gt[99]; - m_A104 += gt[100]; - m_A104 += gt[101]; - m_A104 += gt[102]; - m_A102 += go[98]; - m_A99 += go[99]; - m_A98 += go[100]; - m_A97 += go[101]; - m_A96 += go[102]; - double RHS26 = Idr[98]; - RHS26 += Idr[99]; - RHS26 += Idr[100]; - RHS26 += Idr[101]; - RHS26 += Idr[102]; - m_A113 += gt[103]; - m_A113 += gt[104]; - m_A113 += gt[105]; - m_A113 += gt[106]; - m_A107 += go[103]; - m_A106 += go[104]; - m_A114 += go[105]; - double RHS27 = Idr[103]; - RHS27 += Idr[104]; - RHS27 += Idr[105]; - RHS27 += Idr[106]; - RHS27 -= go[106] * *cnV[106]; - m_A121 += gt[107]; - m_A121 += gt[108]; - m_A121 += gt[109]; - m_A121 += gt[110]; - m_A121 += gt[111]; - m_A118 += go[107]; - m_A117 += go[108]; - m_A120 += go[109]; - m_A116 += go[110]; - m_A115 += go[111]; - double RHS28 = Idr[107]; - RHS28 += Idr[108]; - RHS28 += Idr[109]; - RHS28 += Idr[110]; - RHS28 += Idr[111]; - const double f0 = 1.0 / m_A0; - const double f0_17 = -f0 * m_A41; - m_A43 += m_A1 * f0_17; - RHS17 += f0_17 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_14 = -f1 * m_A34; - m_A35 += m_A3 * f1_14; - RHS14 += f1_14 * RHS1; - const double f1_25 = -f1 * m_A86; - m_A89 += m_A3 * f1_25; - RHS25 += f1_25 * RHS1; - const double f2 = 1.0 / m_A4; - const double f2_15 = -f2 * m_A36; - m_A38 += m_A5 * f2_15; - RHS15 += f2_15 * RHS2; - const double f2_25 = -f2 * m_A87; - m_A93 += m_A5 * f2_25; - RHS25 += f2_25 * RHS2; - const double f3 = 1.0 / m_A6; - const double f3_22 = -f3 * m_A62; - m_A66 += m_A7 * f3_22; - RHS22 += f3_22 * RHS3; - const double f4 = 1.0 / m_A8; - const double f4_16 = -f4 * m_A39; - m_A40 += m_A9 * f4_16; - RHS16 += f4_16 * RHS4; - const double f4_28 = -f4 * m_A115; - m_A117 += m_A9 * f4_28; - RHS28 += f4_28 * RHS4; - const double f5 = 1.0 / m_A10; - const double f5_17 = -f5 * m_A42; - m_A43 += m_A11 * f5_17; - m_A44 += m_A12 * f5_17; - m_A45 += m_A13 * f5_17; - RHS17 += f5_17 * RHS5; - const double f5_22 = -f5 * m_A63; - m_A67 += m_A11 * f5_22; - m_A69 += m_A12 * f5_22; - m_A71 += m_A13 * f5_22; - RHS22 += f5_22 * RHS5; - const double f5_25 = -f5 * m_A88; - m_A90 += m_A11 * f5_25; - m_A91 += m_A12 * f5_25; - m_A93 += m_A13 * f5_25; - RHS25 += f5_25 * RHS5; - const double f6 = 1.0 / m_A14; - const double f6_18 = -f6 * m_A46; - m_A48 += m_A15 * f6_18; - RHS18 += f6_18 * RHS6; - const double f7 = 1.0 / m_A16; - const double f7_22 = -f7 * m_A64; - m_A69 += m_A17 * f7_22; - m_A73 += m_A18 * f7_22; - RHS22 += f7_22 * RHS7; - const double f7_27 = -f7 * m_A106; - m_A109 += m_A17 * f7_27; - m_A113 += m_A18 * f7_27; - RHS27 += f7_27 * RHS7; - const double f8 = 1.0 / m_A19; - const double f8_21 = -f8 * m_A59; - m_A61 += m_A20 * f8_21; - RHS21 += f8_21 * RHS8; - const double f8_28 = -f8 * m_A116; - m_A121 += m_A20 * f8_28; - RHS28 += f8_28 * RHS8; - const double f9 = 1.0 / m_A21; - const double f9_19 = -f9 * m_A51; - m_A52 += m_A22 * f9_19; - RHS19 += f9_19 * RHS9; - const double f9_26 = -f9 * m_A96; - m_A99 += m_A22 * f9_26; - RHS26 += f9_26 * RHS9; - const double f10 = 1.0 / m_A23; - const double f10_20 = -f10 * m_A53; - m_A55 += m_A24 * f10_20; - m_A56 += m_A25 * f10_20; - RHS20 += f10_20 * RHS10; - const double f10_22 = -f10 * m_A65; - m_A68 += m_A24 * f10_22; - m_A69 += m_A25 * f10_22; - RHS22 += f10_22 * RHS10; - const double f11 = 1.0 / m_A26; - const double f11_24 = -f11 * m_A77; - m_A81 += m_A27 * f11_24; - RHS24 += f11_24 * RHS11; - const double f12 = 1.0 / m_A28; - const double f12_23 = -f12 * m_A74; - m_A76 += m_A29 * f12_23; - RHS23 += f12_23 * RHS12; - const double f12_26 = -f12 * m_A97; - m_A104 += m_A29 * f12_26; - RHS26 += f12_26 * RHS12; - const double f13 = 1.0 / m_A30; - const double f13_20 = -f13 * m_A54; - m_A55 += m_A31 * f13_20; - m_A57 += m_A32 * f13_20; - m_A58 += m_A33 * f13_20; - RHS20 += f13_20 * RHS13; - const double f13_24 = -f13 * m_A78; - m_A79 += m_A31 * f13_24; - m_A82 += m_A32 * f13_24; - m_A84 += m_A33 * f13_24; - RHS24 += f13_24 * RHS13; - const double f13_26 = -f13 * m_A98; - m_A100 += m_A31 * f13_26; - m_A102 += m_A32 * f13_26; - m_A104 += m_A33 * f13_26; - RHS26 += f13_26 * RHS13; - const double f14 = 1.0 / m_A35; - const double f14_25 = -f14 * m_A89; - RHS25 += f14_25 * RHS14; - const double f15 = 1.0 / m_A37; - const double f15_22 = -f15 * m_A66; - m_A71 += m_A38 * f15_22; - RHS22 += f15_22 * RHS15; - const double f16 = 1.0 / m_A40; - const double f16_28 = -f16 * m_A117; - RHS28 += f16_28 * RHS16; - const double f17 = 1.0 / m_A43; - const double f17_22 = -f17 * m_A67; - m_A69 += m_A44 * f17_22; - m_A71 += m_A45 * f17_22; - RHS22 += f17_22 * RHS17; - const double f17_25 = -f17 * m_A90; - m_A91 += m_A44 * f17_25; - m_A93 += m_A45 * f17_25; - RHS25 += f17_25 * RHS17; - const double f18 = 1.0 / m_A47; - const double f18_27 = -f18 * m_A107; - m_A108 += m_A48 * f18_27; - m_A113 += m_A49 * f18_27; - m_A114 += m_A50 * f18_27; - RHS27 += f18_27 * RHS18; - const double f18_28 = -f18 * m_A118; - m_A119 += m_A48 * f18_28; - m_A120 += m_A49 * f18_28; - m_A121 += m_A50 * f18_28; - RHS28 += f18_28 * RHS18; - const double f19 = 1.0 / m_A52; - const double f19_26 = -f19 * m_A99; - RHS26 += f19_26 * RHS19; - const double f20 = 1.0 / m_A55; - const double f20_22 = -f20 * m_A68; - m_A69 += m_A56 * f20_22; - m_A70 += m_A57 * f20_22; - m_A72 += m_A58 * f20_22; - RHS22 += f20_22 * RHS20; - const double f20_24 = -f20 * m_A79; - m_A80 += m_A56 * f20_24; - m_A82 += m_A57 * f20_24; - m_A84 += m_A58 * f20_24; - RHS24 += f20_24 * RHS20; - const double f20_26 = -f20 * m_A100; - m_A101 += m_A56 * f20_26; - m_A102 += m_A57 * f20_26; - m_A104 += m_A58 * f20_26; - RHS26 += f20_26 * RHS20; - const double f21 = 1.0 / m_A60; - const double f21_27 = -f21 * m_A108; - m_A114 += m_A61 * f21_27; - RHS27 += f21_27 * RHS21; - const double f21_28 = -f21 * m_A119; - m_A121 += m_A61 * f21_28; - RHS28 += f21_28 * RHS21; - const double f22 = 1.0 / m_A69; - const double f22_24 = -f22 * m_A80; - m_A82 += m_A70 * f22_24; - m_A83 += m_A71 * f22_24; - m_A84 += m_A72 * f22_24; - m_A85 += m_A73 * f22_24; - RHS24 += f22_24 * RHS22; - const double f22_25 = -f22 * m_A91; - m_A92 += m_A70 * f22_25; - m_A93 += m_A71 * f22_25; - m_A94 += m_A72 * f22_25; - m_A95 += m_A73 * f22_25; - RHS25 += f22_25 * RHS22; - const double f22_26 = -f22 * m_A101; - m_A102 += m_A70 * f22_26; - m_A103 += m_A71 * f22_26; - m_A104 += m_A72 * f22_26; - m_A105 += m_A73 * f22_26; - RHS26 += f22_26 * RHS22; - const double f22_27 = -f22 * m_A109; - m_A110 += m_A70 * f22_27; - m_A111 += m_A71 * f22_27; - m_A112 += m_A72 * f22_27; - m_A113 += m_A73 * f22_27; - RHS27 += f22_27 * RHS22; - const double f23 = 1.0 / m_A75; - const double f23_24 = -f23 * m_A81; - m_A84 += m_A76 * f23_24; - RHS24 += f23_24 * RHS23; - const double f24 = 1.0 / m_A82; - const double f24_25 = -f24 * m_A92; - m_A93 += m_A83 * f24_25; - m_A94 += m_A84 * f24_25; - m_A95 += m_A85 * f24_25; - RHS25 += f24_25 * RHS24; - const double f24_26 = -f24 * m_A102; - m_A103 += m_A83 * f24_26; - m_A104 += m_A84 * f24_26; - m_A105 += m_A85 * f24_26; - RHS26 += f24_26 * RHS24; - const double f24_27 = -f24 * m_A110; - m_A111 += m_A83 * f24_27; - m_A112 += m_A84 * f24_27; - m_A113 += m_A85 * f24_27; - RHS27 += f24_27 * RHS24; - const double f25 = 1.0 / m_A93; - const double f25_26 = -f25 * m_A103; - m_A104 += m_A94 * f25_26; - m_A105 += m_A95 * f25_26; - RHS26 += f25_26 * RHS25; - const double f25_27 = -f25 * m_A111; - m_A112 += m_A94 * f25_27; - m_A113 += m_A95 * f25_27; - RHS27 += f25_27 * RHS25; - const double f26 = 1.0 / m_A104; - const double f26_27 = -f26 * m_A112; - m_A113 += m_A105 * f26_27; - RHS27 += f26_27 * RHS26; - const double f27 = 1.0 / m_A113; - const double f27_28 = -f27 * m_A120; - m_A121 += m_A114 * f27_28; - RHS28 += f27_28 * RHS27; - V[28] = RHS28 / m_A121; - double tmp27 = 0.0; - tmp27 += m_A114 * V[28]; - V[27] = (RHS27 - tmp27) / m_A113; - double tmp26 = 0.0; - tmp26 += m_A105 * V[27]; - V[26] = (RHS26 - tmp26) / m_A104; - double tmp25 = 0.0; - tmp25 += m_A94 * V[26]; - tmp25 += m_A95 * V[27]; - V[25] = (RHS25 - tmp25) / m_A93; - double tmp24 = 0.0; - tmp24 += m_A83 * V[25]; - tmp24 += m_A84 * V[26]; - tmp24 += m_A85 * V[27]; - V[24] = (RHS24 - tmp24) / m_A82; - double tmp23 = 0.0; - tmp23 += m_A76 * V[26]; - V[23] = (RHS23 - tmp23) / m_A75; - double tmp22 = 0.0; - tmp22 += m_A70 * V[24]; - tmp22 += m_A71 * V[25]; - tmp22 += m_A72 * V[26]; - tmp22 += m_A73 * V[27]; - V[22] = (RHS22 - tmp22) / m_A69; - double tmp21 = 0.0; - tmp21 += m_A61 * V[28]; - V[21] = (RHS21 - tmp21) / m_A60; - double tmp20 = 0.0; - tmp20 += m_A56 * V[22]; - tmp20 += m_A57 * V[24]; - tmp20 += m_A58 * V[26]; - V[20] = (RHS20 - tmp20) / m_A55; - double tmp19 = 0.0; - V[19] = (RHS19 - tmp19) / m_A52; - double tmp18 = 0.0; - tmp18 += m_A48 * V[21]; - tmp18 += m_A49 * V[27]; - tmp18 += m_A50 * V[28]; - V[18] = (RHS18 - tmp18) / m_A47; - double tmp17 = 0.0; - tmp17 += m_A44 * V[22]; - tmp17 += m_A45 * V[25]; - V[17] = (RHS17 - tmp17) / m_A43; - double tmp16 = 0.0; - V[16] = (RHS16 - tmp16) / m_A40; - double tmp15 = 0.0; - tmp15 += m_A38 * V[25]; - V[15] = (RHS15 - tmp15) / m_A37; - double tmp14 = 0.0; - V[14] = (RHS14 - tmp14) / m_A35; - double tmp13 = 0.0; - tmp13 += m_A31 * V[20]; - tmp13 += m_A32 * V[24]; - tmp13 += m_A33 * V[26]; - V[13] = (RHS13 - tmp13) / m_A30; - double tmp12 = 0.0; - tmp12 += m_A29 * V[26]; - V[12] = (RHS12 - tmp12) / m_A28; - double tmp11 = 0.0; - tmp11 += m_A27 * V[23]; - V[11] = (RHS11 - tmp11) / m_A26; - double tmp10 = 0.0; - tmp10 += m_A24 * V[20]; - tmp10 += m_A25 * V[22]; - V[10] = (RHS10 - tmp10) / m_A23; - double tmp9 = 0.0; - tmp9 += m_A22 * V[19]; - V[9] = (RHS9 - tmp9) / m_A21; - double tmp8 = 0.0; - tmp8 += m_A20 * V[28]; - V[8] = (RHS8 - tmp8) / m_A19; - double tmp7 = 0.0; - tmp7 += m_A17 * V[22]; - tmp7 += m_A18 * V[27]; - V[7] = (RHS7 - tmp7) / m_A16; - double tmp6 = 0.0; - tmp6 += m_A15 * V[21]; - V[6] = (RHS6 - tmp6) / m_A14; - double tmp5 = 0.0; - tmp5 += m_A11 * V[17]; - tmp5 += m_A12 * V[22]; - tmp5 += m_A13 * V[25]; - V[5] = (RHS5 - tmp5) / m_A10; - double tmp4 = 0.0; - tmp4 += m_A9 * V[16]; - V[4] = (RHS4 - tmp4) / m_A8; - double tmp3 = 0.0; - tmp3 += m_A7 * V[15]; - V[3] = (RHS3 - tmp3) / m_A6; - double tmp2 = 0.0; - tmp2 += m_A5 * V[25]; - V[2] = (RHS2 - tmp2) / m_A4; - double tmp1 = 0.0; - tmp1 += m_A3 * V[14]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[17]; - V[0] = (RHS0 - tmp0) / m_A0; -} - -// 280zzzap,sspeedr -static void nl_gcr_123_double_double_864a61c57bac9c38(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - double m_A13(0.0); - double m_A14(0.0); - double m_A15(0.0); - double m_A16(0.0); - double m_A17(0.0); - double m_A18(0.0); - double m_A19(0.0); - double m_A20(0.0); - double m_A21(0.0); - double m_A22(0.0); - double m_A23(0.0); - double m_A24(0.0); - double m_A25(0.0); - double m_A26(0.0); - double m_A27(0.0); - double m_A28(0.0); - double m_A29(0.0); - double m_A30(0.0); - double m_A31(0.0); - double m_A32(0.0); - double m_A33(0.0); - double m_A34(0.0); - double m_A35(0.0); - double m_A36(0.0); - double m_A37(0.0); - double m_A38(0.0); - double m_A39(0.0); - double m_A40(0.0); - double m_A41(0.0); - double m_A42(0.0); - double m_A43(0.0); - double m_A44(0.0); - double m_A45(0.0); - double m_A46(0.0); - double m_A47(0.0); - double m_A48(0.0); - double m_A49(0.0); - double m_A50(0.0); - double m_A51(0.0); - double m_A52(0.0); - double m_A53(0.0); - double m_A54(0.0); - double m_A55(0.0); - double m_A56(0.0); - double m_A57(0.0); - double m_A58(0.0); - double m_A59(0.0); - double m_A60(0.0); - double m_A61(0.0); - double m_A62(0.0); - double m_A63(0.0); - double m_A64(0.0); - double m_A65(0.0); - double m_A66(0.0); - double m_A67(0.0); - double m_A68(0.0); - double m_A69(0.0); - double m_A70(0.0); - double m_A71(0.0); - double m_A72(0.0); - double m_A73(0.0); - double m_A74(0.0); - double m_A75(0.0); - double m_A76(0.0); - double m_A77(0.0); - double m_A78(0.0); - double m_A79(0.0); - double m_A80(0.0); - double m_A81(0.0); - double m_A82(0.0); - double m_A83(0.0); - double m_A84(0.0); - double m_A85(0.0); - double m_A86(0.0); - double m_A87(0.0); - double m_A88(0.0); - double m_A89(0.0); - double m_A90(0.0); - double m_A91(0.0); - double m_A92(0.0); - double m_A93(0.0); - double m_A94(0.0); - double m_A95(0.0); - double m_A96(0.0); - double m_A97(0.0); - double m_A98(0.0); - double m_A99(0.0); - double m_A100(0.0); - double m_A101(0.0); - double m_A102(0.0); - double m_A103(0.0); - double m_A104(0.0); - double m_A105(0.0); - double m_A106(0.0); - double m_A107(0.0); - double m_A108(0.0); - double m_A109(0.0); - double m_A110(0.0); - double m_A111(0.0); - double m_A112(0.0); - double m_A113(0.0); - double m_A114(0.0); - double m_A115(0.0); - double m_A116(0.0); - double m_A117(0.0); - double m_A118(0.0); - double m_A119(0.0); - double m_A120(0.0); - double m_A121(0.0); - double m_A122(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A0 += gt[2]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 += Idr[2]; - RHS0 -= go[1] * *cnV[1]; - RHS0 -= go[2] * *cnV[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A3 += go[3]; - double RHS1 = Idr[3]; - RHS1 += Idr[4]; - RHS1 -= go[4] * *cnV[4]; - m_A4 += gt[5]; - m_A4 += gt[6]; - m_A4 += gt[7]; - m_A4 += gt[8]; - m_A4 += gt[9]; - m_A4 += gt[10]; - m_A4 += gt[11]; - m_A5 += go[5]; - double RHS2 = Idr[5]; - RHS2 += Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 += Idr[9]; - RHS2 += Idr[10]; - RHS2 += Idr[11]; - RHS2 -= go[6] * *cnV[6]; - RHS2 -= go[7] * *cnV[7]; - RHS2 -= go[8] * *cnV[8]; - RHS2 -= go[9] * *cnV[9]; - RHS2 -= go[10] * *cnV[10]; - RHS2 -= go[11] * *cnV[11]; - m_A6 += gt[12]; - m_A6 += gt[13]; - m_A6 += gt[14]; - m_A7 += go[12]; - double RHS3 = Idr[12]; - RHS3 += Idr[13]; - RHS3 += Idr[14]; - RHS3 -= go[13] * *cnV[13]; - RHS3 -= go[14] * *cnV[14]; - m_A8 += gt[15]; - m_A8 += gt[16]; - m_A8 += gt[17]; - m_A8 += gt[18]; - m_A8 += gt[19]; - m_A8 += gt[20]; - m_A8 += gt[21]; - m_A9 += go[15]; - double RHS4 = Idr[15]; - RHS4 += Idr[16]; - RHS4 += Idr[17]; - RHS4 += Idr[18]; - RHS4 += Idr[19]; - RHS4 += Idr[20]; - RHS4 += Idr[21]; - RHS4 -= go[16] * *cnV[16]; - RHS4 -= go[17] * *cnV[17]; - RHS4 -= go[18] * *cnV[18]; - RHS4 -= go[19] * *cnV[19]; - RHS4 -= go[20] * *cnV[20]; - RHS4 -= go[21] * *cnV[21]; - m_A10 += gt[22]; - m_A10 += gt[23]; - m_A11 += go[22]; - double RHS5 = Idr[22]; - RHS5 += Idr[23]; - RHS5 -= go[23] * *cnV[23]; - m_A12 += gt[24]; - m_A12 += gt[25]; - m_A14 += go[24]; - m_A13 += go[25]; - double RHS6 = Idr[24]; - RHS6 += Idr[25]; - m_A15 += gt[26]; - m_A15 += gt[27]; - m_A16 += go[26]; - double RHS7 = Idr[26]; - RHS7 += Idr[27]; - RHS7 -= go[27] * *cnV[27]; - m_A17 += gt[28]; - m_A17 += gt[29]; - m_A18 += go[28]; - double RHS8 = Idr[28]; - RHS8 += Idr[29]; - RHS8 -= go[29] * *cnV[29]; - m_A19 += gt[30]; - m_A19 += gt[31]; - m_A19 += gt[32]; - m_A19 += gt[33]; - m_A19 += gt[34]; - m_A19 += gt[35]; - m_A19 += gt[36]; - m_A20 += go[30]; - double RHS9 = Idr[30]; - RHS9 += Idr[31]; - RHS9 += Idr[32]; - RHS9 += Idr[33]; - RHS9 += Idr[34]; - RHS9 += Idr[35]; - RHS9 += Idr[36]; - RHS9 -= go[31] * *cnV[31]; - RHS9 -= go[32] * *cnV[32]; - RHS9 -= go[33] * *cnV[33]; - RHS9 -= go[34] * *cnV[34]; - RHS9 -= go[35] * *cnV[35]; - RHS9 -= go[36] * *cnV[36]; - m_A21 += gt[37]; - m_A21 += gt[38]; - m_A21 += gt[39]; - m_A22 += go[37]; - double RHS10 = Idr[37]; - RHS10 += Idr[38]; - RHS10 += Idr[39]; - RHS10 -= go[38] * *cnV[38]; - RHS10 -= go[39] * *cnV[39]; - m_A23 += gt[40]; - m_A23 += gt[41]; - m_A23 += gt[42]; - m_A23 += gt[43]; - m_A24 += go[40]; - double RHS11 = Idr[40]; - RHS11 += Idr[41]; - RHS11 += Idr[42]; - RHS11 += Idr[43]; - RHS11 -= go[41] * *cnV[41]; - RHS11 -= go[42] * *cnV[42]; - RHS11 -= go[43] * *cnV[43]; - m_A25 += gt[44]; - m_A25 += gt[45]; - m_A25 += gt[46]; - m_A25 += gt[47]; - m_A25 += gt[48]; - m_A25 += gt[49]; - m_A25 += gt[50]; - m_A26 += go[44]; - double RHS12 = Idr[44]; - RHS12 += Idr[45]; - RHS12 += Idr[46]; - RHS12 += Idr[47]; - RHS12 += Idr[48]; - RHS12 += Idr[49]; - RHS12 += Idr[50]; - RHS12 -= go[45] * *cnV[45]; - RHS12 -= go[46] * *cnV[46]; - RHS12 -= go[47] * *cnV[47]; - RHS12 -= go[48] * *cnV[48]; - RHS12 -= go[49] * *cnV[49]; - RHS12 -= go[50] * *cnV[50]; - m_A27 += gt[51]; - m_A27 += gt[52]; - m_A28 += go[51]; - double RHS13 = Idr[51]; - RHS13 += Idr[52]; - RHS13 -= go[52] * *cnV[52]; - m_A29 += gt[53]; - m_A29 += gt[54]; - m_A30 += go[53]; - double RHS14 = Idr[53]; - RHS14 += Idr[54]; - RHS14 -= go[54] * *cnV[54]; - m_A31 += gt[55]; - m_A31 += gt[56]; - m_A32 += go[55]; - double RHS15 = Idr[55]; - RHS15 += Idr[56]; - RHS15 -= go[56] * *cnV[56]; - m_A33 += gt[57]; - m_A33 += gt[58]; - m_A33 += gt[59]; - m_A33 += gt[60]; - m_A35 += go[57]; - m_A34 += go[58]; - double RHS16 = Idr[57]; - RHS16 += Idr[58]; - RHS16 += Idr[59]; - RHS16 += Idr[60]; - RHS16 -= go[59] * *cnV[59]; - RHS16 -= go[60] * *cnV[60]; - m_A36 += gt[61]; - m_A36 += gt[62]; - m_A36 += gt[63]; - m_A37 += go[61]; - double RHS17 = Idr[61]; - RHS17 += Idr[62]; - RHS17 += Idr[63]; - RHS17 -= go[62] * *cnV[62]; - RHS17 -= go[63] * *cnV[63]; - m_A38 += gt[64]; - m_A38 += gt[65]; - m_A39 += go[64]; - double RHS18 = Idr[64]; - RHS18 += Idr[65]; - RHS18 -= go[65] * *cnV[65]; - m_A40 += gt[66]; - m_A40 += gt[67]; - m_A41 += go[66]; - double RHS19 = Idr[66]; - RHS19 += Idr[67]; - RHS19 -= go[67] * *cnV[67]; - m_A43 += gt[68]; - m_A43 += gt[69]; - m_A43 += gt[70]; - m_A43 += gt[71]; - m_A42 += go[68]; - double RHS20 = Idr[68]; - RHS20 += Idr[69]; - RHS20 += Idr[70]; - RHS20 += Idr[71]; - RHS20 -= go[69] * *cnV[69]; - RHS20 -= go[70] * *cnV[70]; - RHS20 -= go[71] * *cnV[71]; - m_A47 += gt[72]; - m_A47 += gt[73]; - m_A46 += go[72]; - m_A45 += go[73]; - double RHS21 = Idr[72]; - RHS21 += Idr[73]; - m_A51 += gt[74]; - m_A51 += gt[75]; - m_A49 += go[74]; - double RHS22 = Idr[74]; - RHS22 += Idr[75]; - RHS22 -= go[75] * *cnV[75]; - m_A54 += gt[76]; - m_A54 += gt[77]; - m_A54 += gt[78]; - m_A53 += go[76]; - m_A52 += go[77]; - double RHS23 = Idr[76]; - RHS23 += Idr[77]; - RHS23 += Idr[78]; - RHS23 -= go[78] * *cnV[78]; - m_A56 += gt[79]; - m_A56 += gt[80]; - m_A56 += gt[81]; - m_A56 += gt[82]; - m_A55 += go[79]; - m_A57 += go[80]; - double RHS24 = Idr[79]; - RHS24 += Idr[80]; - RHS24 += Idr[81]; - RHS24 += Idr[82]; - RHS24 -= go[81] * *cnV[81]; - RHS24 -= go[82] * *cnV[82]; - m_A59 += gt[83]; - m_A59 += gt[84]; - m_A59 += gt[85]; - m_A59 += gt[86]; - m_A58 += go[83]; - m_A60 += go[84]; - double RHS25 = Idr[83]; - RHS25 += Idr[84]; - RHS25 += Idr[85]; - RHS25 += Idr[86]; - RHS25 -= go[85] * *cnV[85]; - RHS25 -= go[86] * *cnV[86]; - m_A62 += gt[87]; - m_A62 += gt[88]; - m_A63 += go[87]; - m_A61 += go[88]; - double RHS26 = Idr[87]; - RHS26 += Idr[88]; - m_A67 += gt[89]; - m_A67 += gt[90]; - m_A67 += gt[91]; - m_A67 += gt[92]; - m_A67 += gt[93]; - m_A67 += gt[94]; - m_A64 += go[89]; - m_A65 += go[90]; - m_A69 += go[91]; - m_A68 += go[92]; - double RHS27 = Idr[89]; - RHS27 += Idr[90]; - RHS27 += Idr[91]; - RHS27 += Idr[92]; - RHS27 += Idr[93]; - RHS27 += Idr[94]; - RHS27 -= go[93] * *cnV[93]; - RHS27 -= go[94] * *cnV[94]; - m_A72 += gt[95]; - m_A72 += gt[96]; - m_A72 += gt[97]; - m_A72 += gt[98]; - m_A71 += go[95]; - m_A73 += go[96]; - double RHS28 = Idr[95]; - RHS28 += Idr[96]; - RHS28 += Idr[97]; - RHS28 += Idr[98]; - RHS28 -= go[97] * *cnV[97]; - RHS28 -= go[98] * *cnV[98]; - m_A76 += gt[99]; - m_A76 += gt[100]; - m_A76 += gt[101]; - m_A76 += gt[102]; - m_A77 += go[99]; - m_A78 += go[100]; - m_A74 += go[101]; - m_A75 += go[102]; - double RHS29 = Idr[99]; - RHS29 += Idr[100]; - RHS29 += Idr[101]; - RHS29 += Idr[102]; - m_A81 += gt[103]; - m_A81 += gt[104]; - m_A81 += gt[105]; - m_A80 += go[103]; - m_A79 += go[104]; - double RHS30 = Idr[103]; - RHS30 += Idr[104]; - RHS30 += Idr[105]; - RHS30 -= go[105] * *cnV[105]; - m_A84 += gt[106]; - m_A84 += gt[107]; - m_A82 += go[106]; - m_A83 += go[107]; - double RHS31 = Idr[106]; - RHS31 += Idr[107]; - m_A91 += gt[108]; - m_A91 += gt[109]; - m_A91 += gt[110]; - m_A91 += gt[111]; - m_A91 += gt[112]; - m_A86 += go[108]; - m_A90 += go[109]; - m_A88 += go[110]; - m_A85 += go[111]; - m_A87 += go[112]; - double RHS32 = Idr[108]; - RHS32 += Idr[109]; - RHS32 += Idr[110]; - RHS32 += Idr[111]; - RHS32 += Idr[112]; - m_A99 += gt[113]; - m_A99 += gt[114]; - m_A99 += gt[115]; - m_A99 += gt[116]; - m_A99 += gt[117]; - m_A96 += go[113]; - m_A100 += go[114]; - m_A97 += go[115]; - m_A94 += go[116]; - m_A95 += go[117]; - double RHS33 = Idr[113]; - RHS33 += Idr[114]; - RHS33 += Idr[115]; - RHS33 += Idr[116]; - RHS33 += Idr[117]; - m_A106 += gt[118]; - m_A106 += gt[119]; - m_A106 += gt[120]; - m_A106 += gt[121]; - m_A103 += go[118]; - m_A104 += go[119]; - m_A101 += go[120]; - m_A102 += go[121]; - double RHS34 = Idr[118]; - RHS34 += Idr[119]; - RHS34 += Idr[120]; - RHS34 += Idr[121]; - m_A111 += gt[122]; - m_A111 += gt[123]; - m_A111 += gt[124]; - m_A111 += gt[125]; - m_A108 += go[122]; - m_A109 += go[123]; - double RHS35 = Idr[122]; - RHS35 += Idr[123]; - RHS35 += Idr[124]; - RHS35 += Idr[125]; - RHS35 -= go[124] * *cnV[124]; - RHS35 -= go[125] * *cnV[125]; - m_A122 += gt[126]; - m_A122 += gt[127]; - m_A122 += gt[128]; - m_A122 += gt[129]; - m_A122 += gt[130]; - m_A122 += gt[131]; - m_A113 += go[126]; - m_A117 += go[127]; - m_A120 += go[128]; - m_A114 += go[129]; - double RHS36 = Idr[126]; - RHS36 += Idr[127]; - RHS36 += Idr[128]; - RHS36 += Idr[129]; - RHS36 += Idr[130]; - RHS36 += Idr[131]; - RHS36 -= go[130] * *cnV[130]; - RHS36 -= go[131] * *cnV[131]; - const double f0 = 1.0 / m_A0; - const double f0_24 = -f0 * m_A55; - m_A57 += m_A1 * f0_24; - RHS24 += f0_24 * RHS0; - const double f0_32 = -f0 * m_A85; - m_A91 += m_A1 * f0_32; - RHS32 += f0_32 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_32 = -f1 * m_A86; - m_A91 += m_A3 * f1_32; - RHS32 += f1_32 * RHS1; - const double f2 = 1.0 / m_A4; - const double f2_27 = -f2 * m_A64; - m_A66 += m_A5 * f2_27; - RHS27 += f2_27 * RHS2; - const double f3 = 1.0 / m_A6; - const double f3_25 = -f3 * m_A58; - m_A60 += m_A7 * f3_25; - RHS25 += f3_25 * RHS3; - const double f3_34 = -f3 * m_A101; - m_A106 += m_A7 * f3_34; - RHS34 += f3_34 * RHS3; - const double f4 = 1.0 / m_A8; - const double f4_20 = -f4 * m_A42; - m_A44 += m_A9 * f4_20; - RHS20 += f4_20 * RHS4; - const double f5 = 1.0 / m_A10; - const double f5_21 = -f5 * m_A45; - m_A47 += m_A11 * f5_21; - RHS21 += f5_21 * RHS5; - const double f5_32 = -f5 * m_A87; - m_A88 += m_A11 * f5_32; - RHS32 += f5_32 * RHS5; - const double f6 = 1.0 / m_A12; - const double f6_21 = -f6 * m_A46; - m_A47 += m_A13 * f6_21; - m_A48 += m_A14 * f6_21; - RHS21 += f6_21 * RHS6; - const double f6_22 = -f6 * m_A49; - m_A50 += m_A13 * f6_22; - m_A51 += m_A14 * f6_22; - RHS22 += f6_22 * RHS6; - const double f7 = 1.0 / m_A15; - const double f7_23 = -f7 * m_A52; - m_A54 += m_A16 * f7_23; - RHS23 += f7_23 * RHS7; - const double f7_34 = -f7 * m_A102; - m_A103 += m_A16 * f7_34; - RHS34 += f7_34 * RHS7; - const double f8 = 1.0 / m_A17; - const double f8_23 = -f8 * m_A53; - m_A54 += m_A18 * f8_23; - RHS23 += f8_23 * RHS8; - const double f9 = 1.0 / m_A19; - const double f9_36 = -f9 * m_A113; - m_A116 += m_A20 * f9_36; - RHS36 += f9_36 * RHS9; - const double f10 = 1.0 / m_A21; - const double f10_28 = -f10 * m_A71; - m_A73 += m_A22 * f10_28; - RHS28 += f10_28 * RHS10; - const double f10_33 = -f10 * m_A94; - m_A99 += m_A22 * f10_33; - RHS33 += f10_33 * RHS10; - const double f13 = 1.0 / m_A27; - const double f13_26 = -f13 * m_A61; - m_A62 += m_A28 * f13_26; - RHS26 += f13_26 * RHS13; - const double f13_33 = -f13 * m_A95; - m_A97 += m_A28 * f13_33; - RHS33 += f13_33 * RHS13; - const double f14 = 1.0 / m_A29; - const double f14_33 = -f14 * m_A96; - m_A99 += m_A30 * f14_33; - RHS33 += f14_33 * RHS14; - const double f15 = 1.0 / m_A31; - const double f15_31 = -f15 * m_A82; - m_A84 += m_A32 * f15_31; - RHS31 += f15_31 * RHS15; - const double f16 = 1.0 / m_A33; - const double f16_27 = -f16 * m_A65; - m_A67 += m_A34 * f16_27; - m_A70 += m_A35 * f16_27; - RHS27 += f16_27 * RHS16; - const double f16_36 = -f16 * m_A114; - m_A115 += m_A34 * f16_36; - m_A122 += m_A35 * f16_36; - RHS36 += f16_36 * RHS16; - const double f17 = 1.0 / m_A36; - const double f17_29 = -f17 * m_A74; - m_A76 += m_A37 * f17_29; - RHS29 += f17_29 * RHS17; - const double f17_35 = -f17 * m_A108; - m_A109 += m_A37 * f17_35; - RHS35 += f17_35 * RHS17; - const double f18 = 1.0 / m_A38; - const double f18_29 = -f18 * m_A75; - m_A77 += m_A39 * f18_29; - RHS29 += f18_29 * RHS18; - const double f18_30 = -f18 * m_A79; - m_A81 += m_A39 * f18_30; - RHS30 += f18_30 * RHS18; - const double f19 = 1.0 / m_A40; - const double f19_30 = -f19 * m_A80; - m_A81 += m_A41 * f19_30; - RHS30 += f19_30 * RHS19; - const double f21 = 1.0 / m_A47; - const double f21_22 = -f21 * m_A50; - m_A51 += m_A48 * f21_22; - RHS22 += f21_22 * RHS21; - const double f21_32 = -f21 * m_A88; - m_A89 += m_A48 * f21_32; - RHS32 += f21_32 * RHS21; - const double f22 = 1.0 / m_A51; - const double f22_32 = -f22 * m_A89; - RHS32 += f22_32 * RHS22; - const double f23 = 1.0 / m_A54; - const double f23_34 = -f23 * m_A103; - RHS34 += f23_34 * RHS23; - const double f24 = 1.0 / m_A56; - const double f24_27 = -f24 * m_A66; - m_A68 += m_A57 * f24_27; - RHS27 += f24_27 * RHS24; - const double f26 = 1.0 / m_A62; - const double f26_31 = -f26 * m_A83; - m_A84 += m_A63 * f26_31; - RHS31 += f26_31 * RHS26; - const double f26_33 = -f26 * m_A97; - m_A98 += m_A63 * f26_33; - RHS33 += f26_33 * RHS26; - const double f27 = 1.0 / m_A67; - const double f27_32 = -f27 * m_A90; - m_A91 += m_A68 * f27_32; - m_A92 += m_A69 * f27_32; - m_A93 += m_A70 * f27_32; - RHS32 += f27_32 * RHS27; - const double f27_34 = -f27 * m_A104; - m_A105 += m_A68 * f27_34; - m_A106 += m_A69 * f27_34; - m_A107 += m_A70 * f27_34; - RHS34 += f27_34 * RHS27; - const double f27_36 = -f27 * m_A115; - m_A119 += m_A68 * f27_36; - m_A121 += m_A69 * f27_36; - m_A122 += m_A70 * f27_36; - RHS36 += f27_36 * RHS27; - const double f28 = 1.0 / m_A72; - const double f28_36 = -f28 * m_A116; - m_A120 += m_A73 * f28_36; - RHS36 += f28_36 * RHS28; - const double f29 = 1.0 / m_A76; - const double f29_35 = -f29 * m_A109; - m_A110 += m_A77 * f29_35; - m_A112 += m_A78 * f29_35; - RHS35 += f29_35 * RHS29; - const double f29_36 = -f29 * m_A117; - m_A118 += m_A77 * f29_36; - m_A122 += m_A78 * f29_36; - RHS36 += f29_36 * RHS29; - const double f30 = 1.0 / m_A81; - const double f30_35 = -f30 * m_A110; - RHS35 += f30_35 * RHS30; - const double f30_36 = -f30 * m_A118; - RHS36 += f30_36 * RHS30; - const double f31 = 1.0 / m_A84; - const double f31_33 = -f31 * m_A98; - RHS33 += f31_33 * RHS31; - const double f32 = 1.0 / m_A91; - const double f32_34 = -f32 * m_A105; - m_A106 += m_A92 * f32_34; - m_A107 += m_A93 * f32_34; - RHS34 += f32_34 * RHS32; - const double f32_36 = -f32 * m_A119; - m_A121 += m_A92 * f32_36; - m_A122 += m_A93 * f32_36; - RHS36 += f32_36 * RHS32; - const double f33 = 1.0 / m_A99; - const double f33_36 = -f33 * m_A120; - m_A122 += m_A100 * f33_36; - RHS36 += f33_36 * RHS33; - const double f34 = 1.0 / m_A106; - const double f34_36 = -f34 * m_A121; - m_A122 += m_A107 * f34_36; - RHS36 += f34_36 * RHS34; - V[36] = RHS36 / m_A122; - double tmp35 = 0.0; - tmp35 += m_A112 * V[36]; - V[35] = (RHS35 - tmp35) / m_A111; - double tmp34 = 0.0; - tmp34 += m_A107 * V[36]; - V[34] = (RHS34 - tmp34) / m_A106; - double tmp33 = 0.0; - tmp33 += m_A100 * V[36]; - V[33] = (RHS33 - tmp33) / m_A99; - double tmp32 = 0.0; - tmp32 += m_A92 * V[34]; - tmp32 += m_A93 * V[36]; - V[32] = (RHS32 - tmp32) / m_A91; - double tmp31 = 0.0; - V[31] = (RHS31 - tmp31) / m_A84; - double tmp30 = 0.0; - V[30] = (RHS30 - tmp30) / m_A81; - double tmp29 = 0.0; - tmp29 += m_A77 * V[30]; - tmp29 += m_A78 * V[36]; - V[29] = (RHS29 - tmp29) / m_A76; - double tmp28 = 0.0; - tmp28 += m_A73 * V[33]; - V[28] = (RHS28 - tmp28) / m_A72; - double tmp27 = 0.0; - tmp27 += m_A68 * V[32]; - tmp27 += m_A69 * V[34]; - tmp27 += m_A70 * V[36]; - V[27] = (RHS27 - tmp27) / m_A67; - double tmp26 = 0.0; - tmp26 += m_A63 * V[31]; - V[26] = (RHS26 - tmp26) / m_A62; - double tmp25 = 0.0; - tmp25 += m_A60 * V[34]; - V[25] = (RHS25 - tmp25) / m_A59; - double tmp24 = 0.0; - tmp24 += m_A57 * V[32]; - V[24] = (RHS24 - tmp24) / m_A56; - double tmp23 = 0.0; - V[23] = (RHS23 - tmp23) / m_A54; - double tmp22 = 0.0; - V[22] = (RHS22 - tmp22) / m_A51; - double tmp21 = 0.0; - tmp21 += m_A48 * V[22]; - V[21] = (RHS21 - tmp21) / m_A47; - double tmp20 = 0.0; - tmp20 += m_A44 * V[25]; - V[20] = (RHS20 - tmp20) / m_A43; - double tmp19 = 0.0; - tmp19 += m_A41 * V[30]; - V[19] = (RHS19 - tmp19) / m_A40; - double tmp18 = 0.0; - tmp18 += m_A39 * V[30]; - V[18] = (RHS18 - tmp18) / m_A38; - double tmp17 = 0.0; - tmp17 += m_A37 * V[29]; - V[17] = (RHS17 - tmp17) / m_A36; - double tmp16 = 0.0; - tmp16 += m_A34 * V[27]; - tmp16 += m_A35 * V[36]; - V[16] = (RHS16 - tmp16) / m_A33; - double tmp15 = 0.0; - tmp15 += m_A32 * V[31]; - V[15] = (RHS15 - tmp15) / m_A31; - double tmp14 = 0.0; - tmp14 += m_A30 * V[33]; - V[14] = (RHS14 - tmp14) / m_A29; - double tmp13 = 0.0; - tmp13 += m_A28 * V[26]; - V[13] = (RHS13 - tmp13) / m_A27; - double tmp12 = 0.0; - tmp12 += m_A26 * V[35]; - V[12] = (RHS12 - tmp12) / m_A25; - double tmp11 = 0.0; - tmp11 += m_A24 * V[12]; - V[11] = (RHS11 - tmp11) / m_A23; - double tmp10 = 0.0; - tmp10 += m_A22 * V[33]; - V[10] = (RHS10 - tmp10) / m_A21; - double tmp9 = 0.0; - tmp9 += m_A20 * V[28]; - V[9] = (RHS9 - tmp9) / m_A19; - double tmp8 = 0.0; - tmp8 += m_A18 * V[23]; - V[8] = (RHS8 - tmp8) / m_A17; - double tmp7 = 0.0; - tmp7 += m_A16 * V[23]; - V[7] = (RHS7 - tmp7) / m_A15; - double tmp6 = 0.0; - tmp6 += m_A13 * V[21]; - tmp6 += m_A14 * V[22]; - V[6] = (RHS6 - tmp6) / m_A12; - double tmp5 = 0.0; - tmp5 += m_A11 * V[21]; - V[5] = (RHS5 - tmp5) / m_A10; - double tmp4 = 0.0; - tmp4 += m_A9 * V[25]; - V[4] = (RHS4 - tmp4) / m_A8; - double tmp3 = 0.0; - tmp3 += m_A7 * V[34]; - V[3] = (RHS3 - tmp3) / m_A6; - double tmp2 = 0.0; - tmp2 += m_A5 * V[24]; - V[2] = (RHS2 - tmp2) / m_A4; - double tmp1 = 0.0; - tmp1 += m_A3 * V[32]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[32]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // 280zzzap static void nl_gcr_149_double_double_fc9971724787b82b(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -3844,398 +1510,6 @@ static void nl_gcr_149_double_double_fc9971724787b82b(double * __restrict V, con V[0] = (RHS0 - tmp0) / m_A0; } -// 280zzzap,sspeedr -static void nl_gcr_57_double_double_bb501e6a23177009(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - double m_A13(0.0); - double m_A14(0.0); - double m_A15(0.0); - double m_A16(0.0); - double m_A17(0.0); - double m_A18(0.0); - double m_A19(0.0); - double m_A20(0.0); - double m_A21(0.0); - double m_A22(0.0); - double m_A23(0.0); - double m_A24(0.0); - double m_A25(0.0); - double m_A26(0.0); - double m_A27(0.0); - double m_A28(0.0); - double m_A29(0.0); - double m_A30(0.0); - double m_A31(0.0); - double m_A32(0.0); - double m_A33(0.0); - double m_A34(0.0); - double m_A35(0.0); - double m_A36(0.0); - double m_A37(0.0); - double m_A38(0.0); - double m_A39(0.0); - double m_A40(0.0); - double m_A41(0.0); - double m_A42(0.0); - double m_A43(0.0); - double m_A44(0.0); - double m_A45(0.0); - double m_A46(0.0); - double m_A47(0.0); - double m_A48(0.0); - double m_A49(0.0); - double m_A50(0.0); - double m_A51(0.0); - double m_A52(0.0); - double m_A53(0.0); - double m_A54(0.0); - double m_A55(0.0); - double m_A56(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A0 += gt[2]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 += Idr[2]; - RHS0 -= go[1] * *cnV[1]; - RHS0 -= go[2] * *cnV[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A3 += go[3]; - double RHS1 = Idr[3]; - RHS1 += Idr[4]; - RHS1 -= go[4] * *cnV[4]; - m_A4 += gt[5]; - m_A4 += gt[6]; - m_A4 += gt[7]; - m_A4 += gt[8]; - m_A4 += gt[9]; - m_A4 += gt[10]; - m_A4 += gt[11]; - m_A5 += go[5]; - double RHS2 = Idr[5]; - RHS2 += Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 += Idr[9]; - RHS2 += Idr[10]; - RHS2 += Idr[11]; - RHS2 -= go[6] * *cnV[6]; - RHS2 -= go[7] * *cnV[7]; - RHS2 -= go[8] * *cnV[8]; - RHS2 -= go[9] * *cnV[9]; - RHS2 -= go[10] * *cnV[10]; - RHS2 -= go[11] * *cnV[11]; - m_A6 += gt[12]; - m_A6 += gt[13]; - m_A6 += gt[14]; - m_A7 += go[12]; - double RHS3 = Idr[12]; - RHS3 += Idr[13]; - RHS3 += Idr[14]; - RHS3 -= go[13] * *cnV[13]; - RHS3 -= go[14] * *cnV[14]; - m_A8 += gt[15]; - m_A8 += gt[16]; - m_A8 += gt[17]; - m_A8 += gt[18]; - m_A8 += gt[19]; - m_A8 += gt[20]; - m_A8 += gt[21]; - m_A9 += go[15]; - double RHS4 = Idr[15]; - RHS4 += Idr[16]; - RHS4 += Idr[17]; - RHS4 += Idr[18]; - RHS4 += Idr[19]; - RHS4 += Idr[20]; - RHS4 += Idr[21]; - RHS4 -= go[16] * *cnV[16]; - RHS4 -= go[17] * *cnV[17]; - RHS4 -= go[18] * *cnV[18]; - RHS4 -= go[19] * *cnV[19]; - RHS4 -= go[20] * *cnV[20]; - RHS4 -= go[21] * *cnV[21]; - m_A10 += gt[22]; - m_A10 += gt[23]; - m_A11 += go[22]; - double RHS5 = Idr[22]; - RHS5 += Idr[23]; - RHS5 -= go[23] * *cnV[23]; - m_A12 += gt[24]; - m_A12 += gt[25]; - m_A14 += go[24]; - m_A13 += go[25]; - double RHS6 = Idr[24]; - RHS6 += Idr[25]; - m_A15 += gt[26]; - m_A15 += gt[27]; - m_A16 += go[26]; - double RHS7 = Idr[26]; - RHS7 += Idr[27]; - RHS7 -= go[27] * *cnV[27]; - m_A17 += gt[28]; - m_A17 += gt[29]; - m_A18 += go[28]; - double RHS8 = Idr[28]; - RHS8 += Idr[29]; - RHS8 -= go[29] * *cnV[29]; - m_A20 += gt[30]; - m_A20 += gt[31]; - m_A20 += gt[32]; - m_A20 += gt[33]; - m_A19 += go[30]; - double RHS9 = Idr[30]; - RHS9 += Idr[31]; - RHS9 += Idr[32]; - RHS9 += Idr[33]; - RHS9 -= go[31] * *cnV[31]; - RHS9 -= go[32] * *cnV[32]; - RHS9 -= go[33] * *cnV[33]; - m_A24 += gt[34]; - m_A24 += gt[35]; - m_A23 += go[34]; - m_A22 += go[35]; - double RHS10 = Idr[34]; - RHS10 += Idr[35]; - m_A27 += gt[36]; - m_A27 += gt[37]; - m_A27 += gt[38]; - m_A27 += gt[39]; - m_A26 += go[36]; - m_A28 += go[37]; - double RHS11 = Idr[36]; - RHS11 += Idr[37]; - RHS11 += Idr[38]; - RHS11 += Idr[39]; - RHS11 -= go[38] * *cnV[38]; - RHS11 -= go[39] * *cnV[39]; - m_A31 += gt[40]; - m_A31 += gt[41]; - m_A31 += gt[42]; - m_A31 += gt[43]; - m_A31 += gt[44]; - m_A31 += gt[45]; - m_A29 += go[40]; - m_A33 += go[41]; - m_A32 += go[42]; - double RHS12 = Idr[40]; - RHS12 += Idr[41]; - RHS12 += Idr[42]; - RHS12 += Idr[43]; - RHS12 += Idr[44]; - RHS12 += Idr[45]; - RHS12 -= go[43] * *cnV[43]; - RHS12 -= go[44] * *cnV[44]; - RHS12 -= go[45] * *cnV[45]; - m_A36 += gt[46]; - m_A36 += gt[47]; - m_A34 += go[46]; - double RHS13 = Idr[46]; - RHS13 += Idr[47]; - RHS13 -= go[47] * *cnV[47]; - m_A39 += gt[48]; - m_A39 += gt[49]; - m_A39 += gt[50]; - m_A38 += go[48]; - m_A37 += go[49]; - double RHS14 = Idr[48]; - RHS14 += Idr[49]; - RHS14 += Idr[50]; - RHS14 -= go[50] * *cnV[50]; - m_A41 += gt[51]; - m_A41 += gt[52]; - m_A41 += gt[53]; - m_A41 += gt[54]; - m_A40 += go[51]; - m_A42 += go[52]; - double RHS15 = Idr[51]; - RHS15 += Idr[52]; - RHS15 += Idr[53]; - RHS15 += Idr[54]; - RHS15 -= go[53] * *cnV[53]; - RHS15 -= go[54] * *cnV[54]; - m_A49 += gt[55]; - m_A49 += gt[56]; - m_A49 += gt[57]; - m_A49 += gt[58]; - m_A49 += gt[59]; - m_A44 += go[55]; - m_A47 += go[56]; - m_A46 += go[57]; - m_A43 += go[58]; - m_A45 += go[59]; - double RHS16 = Idr[55]; - RHS16 += Idr[56]; - RHS16 += Idr[57]; - RHS16 += Idr[58]; - RHS16 += Idr[59]; - m_A56 += gt[60]; - m_A56 += gt[61]; - m_A56 += gt[62]; - m_A56 += gt[63]; - m_A54 += go[60]; - m_A53 += go[61]; - m_A51 += go[62]; - m_A52 += go[63]; - double RHS17 = Idr[60]; - RHS17 += Idr[61]; - RHS17 += Idr[62]; - RHS17 += Idr[63]; - const double f0 = 1.0 / m_A0; - const double f0_11 = -f0 * m_A26; - m_A28 += m_A1 * f0_11; - RHS11 += f0_11 * RHS0; - const double f0_16 = -f0 * m_A43; - m_A49 += m_A1 * f0_16; - RHS16 += f0_16 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_16 = -f1 * m_A44; - m_A49 += m_A3 * f1_16; - RHS16 += f1_16 * RHS1; - const double f2 = 1.0 / m_A4; - const double f2_12 = -f2 * m_A29; - m_A30 += m_A5 * f2_12; - RHS12 += f2_12 * RHS2; - const double f3 = 1.0 / m_A6; - const double f3_15 = -f3 * m_A40; - m_A42 += m_A7 * f3_15; - RHS15 += f3_15 * RHS3; - const double f3_17 = -f3 * m_A51; - m_A56 += m_A7 * f3_17; - RHS17 += f3_17 * RHS3; - const double f4 = 1.0 / m_A8; - const double f4_9 = -f4 * m_A19; - m_A21 += m_A9 * f4_9; - RHS9 += f4_9 * RHS4; - const double f5 = 1.0 / m_A10; - const double f5_10 = -f5 * m_A22; - m_A24 += m_A11 * f5_10; - RHS10 += f5_10 * RHS5; - const double f5_16 = -f5 * m_A45; - m_A46 += m_A11 * f5_16; - RHS16 += f5_16 * RHS5; - const double f6 = 1.0 / m_A12; - const double f6_10 = -f6 * m_A23; - m_A24 += m_A13 * f6_10; - m_A25 += m_A14 * f6_10; - RHS10 += f6_10 * RHS6; - const double f6_13 = -f6 * m_A34; - m_A35 += m_A13 * f6_13; - m_A36 += m_A14 * f6_13; - RHS13 += f6_13 * RHS6; - const double f7 = 1.0 / m_A15; - const double f7_14 = -f7 * m_A37; - m_A39 += m_A16 * f7_14; - RHS14 += f7_14 * RHS7; - const double f7_17 = -f7 * m_A52; - m_A54 += m_A16 * f7_17; - RHS17 += f7_17 * RHS7; - const double f8 = 1.0 / m_A17; - const double f8_14 = -f8 * m_A38; - m_A39 += m_A18 * f8_14; - RHS14 += f8_14 * RHS8; - const double f10 = 1.0 / m_A24; - const double f10_13 = -f10 * m_A35; - m_A36 += m_A25 * f10_13; - RHS13 += f10_13 * RHS10; - const double f10_16 = -f10 * m_A46; - m_A48 += m_A25 * f10_16; - RHS16 += f10_16 * RHS10; - const double f11 = 1.0 / m_A27; - const double f11_12 = -f11 * m_A30; - m_A32 += m_A28 * f11_12; - RHS12 += f11_12 * RHS11; - const double f12 = 1.0 / m_A31; - const double f12_16 = -f12 * m_A47; - m_A49 += m_A32 * f12_16; - m_A50 += m_A33 * f12_16; - RHS16 += f12_16 * RHS12; - const double f12_17 = -f12 * m_A53; - m_A55 += m_A32 * f12_17; - m_A56 += m_A33 * f12_17; - RHS17 += f12_17 * RHS12; - const double f13 = 1.0 / m_A36; - const double f13_16 = -f13 * m_A48; - RHS16 += f13_16 * RHS13; - const double f14 = 1.0 / m_A39; - const double f14_17 = -f14 * m_A54; - RHS17 += f14_17 * RHS14; - const double f16 = 1.0 / m_A49; - const double f16_17 = -f16 * m_A55; - m_A56 += m_A50 * f16_17; - RHS17 += f16_17 * RHS16; - V[17] = RHS17 / m_A56; - double tmp16 = 0.0; - tmp16 += m_A50 * V[17]; - V[16] = (RHS16 - tmp16) / m_A49; - double tmp15 = 0.0; - tmp15 += m_A42 * V[17]; - V[15] = (RHS15 - tmp15) / m_A41; - double tmp14 = 0.0; - V[14] = (RHS14 - tmp14) / m_A39; - double tmp13 = 0.0; - V[13] = (RHS13 - tmp13) / m_A36; - double tmp12 = 0.0; - tmp12 += m_A32 * V[16]; - tmp12 += m_A33 * V[17]; - V[12] = (RHS12 - tmp12) / m_A31; - double tmp11 = 0.0; - tmp11 += m_A28 * V[16]; - V[11] = (RHS11 - tmp11) / m_A27; - double tmp10 = 0.0; - tmp10 += m_A25 * V[13]; - V[10] = (RHS10 - tmp10) / m_A24; - double tmp9 = 0.0; - tmp9 += m_A21 * V[15]; - V[9] = (RHS9 - tmp9) / m_A20; - double tmp8 = 0.0; - tmp8 += m_A18 * V[14]; - V[8] = (RHS8 - tmp8) / m_A17; - double tmp7 = 0.0; - tmp7 += m_A16 * V[14]; - V[7] = (RHS7 - tmp7) / m_A15; - double tmp6 = 0.0; - tmp6 += m_A13 * V[10]; - tmp6 += m_A14 * V[13]; - V[6] = (RHS6 - tmp6) / m_A12; - double tmp5 = 0.0; - tmp5 += m_A11 * V[10]; - V[5] = (RHS5 - tmp5) / m_A10; - double tmp4 = 0.0; - tmp4 += m_A9 * V[15]; - V[4] = (RHS4 - tmp4) / m_A8; - double tmp3 = 0.0; - tmp3 += m_A7 * V[17]; - V[3] = (RHS3 - tmp3) / m_A6; - double tmp2 = 0.0; - tmp2 += m_A5 * V[11]; - V[2] = (RHS2 - tmp2) / m_A4; - double tmp1 = 0.0; - tmp1 += m_A3 * V[16]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[16]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // 280zzzap static void nl_gcr_95_double_double_24643c159711f292(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -6698,107 +3972,6 @@ static void nl_gcr_67_double_double_ee2cacaa15d32491(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// astrob,rebound -static void nl_gcr_13_double_double_a41a44bd5c424f88(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A0 += gt[2]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 += Idr[2]; - RHS0 -= go[1] * *cnV[1]; - RHS0 -= go[2] * *cnV[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A2 += gt[5]; - m_A3 += go[3]; - double RHS1 = Idr[3]; - RHS1 += Idr[4]; - RHS1 += Idr[5]; - RHS1 -= go[4] * *cnV[4]; - RHS1 -= go[5] * *cnV[5]; - m_A4 += gt[6]; - m_A4 += gt[7]; - m_A4 += gt[8]; - m_A5 += go[6]; - double RHS2 = Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 -= go[7] * *cnV[7]; - RHS2 -= go[8] * *cnV[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A6 += gt[11]; - m_A7 += go[9]; - double RHS3 = Idr[9]; - RHS3 += Idr[10]; - RHS3 += Idr[11]; - RHS3 -= go[10] * *cnV[10]; - RHS3 -= go[11] * *cnV[11]; - m_A12 += gt[12]; - m_A12 += gt[13]; - m_A12 += gt[14]; - m_A12 += gt[15]; - m_A12 += gt[16]; - m_A11 += go[12]; - m_A10 += go[13]; - m_A9 += go[14]; - m_A8 += go[15]; - double RHS4 = Idr[12]; - RHS4 += Idr[13]; - RHS4 += Idr[14]; - RHS4 += Idr[15]; - RHS4 += Idr[16]; - RHS4 -= go[16] * *cnV[16]; - const double f0 = 1.0 / m_A0; - const double f0_4 = -f0 * m_A8; - m_A12 += m_A1 * f0_4; - RHS4 += f0_4 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_4 = -f1 * m_A9; - m_A12 += m_A3 * f1_4; - RHS4 += f1_4 * RHS1; - const double f2 = 1.0 / m_A4; - const double f2_4 = -f2 * m_A10; - m_A12 += m_A5 * f2_4; - RHS4 += f2_4 * RHS2; - const double f3 = 1.0 / m_A6; - const double f3_4 = -f3 * m_A11; - m_A12 += m_A7 * f3_4; - RHS4 += f3_4 * RHS3; - V[4] = RHS4 / m_A12; - double tmp3 = 0.0; - tmp3 += m_A7 * V[4]; - V[3] = (RHS3 - tmp3) / m_A6; - double tmp2 = 0.0; - tmp2 += m_A5 * V[4]; - V[2] = (RHS2 - tmp2) / m_A4; - double tmp1 = 0.0; - tmp1 += m_A3 * V[4]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[4]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // astrob static void nl_gcr_154_double_double_13833bf8c127deaa(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -18473,60 +15646,6 @@ static void nl_gcr_77_double_double_437326911721091(double * __restrict V, const V[0] = (RHS0 - tmp0) / m_A0; } -// brdrline,stuntcyc -static void nl_gcr_7_double_double_59cb6bf7cb9d17dc(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A3 += go[2]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 -= go[3] * *cnV[3]; - m_A6 += gt[4]; - m_A6 += gt[5]; - m_A6 += gt[6]; - m_A6 += gt[7]; - m_A5 += go[4]; - m_A4 += go[5]; - double RHS2 = Idr[4]; - RHS2 += Idr[5]; - RHS2 += Idr[6]; - RHS2 += Idr[7]; - RHS2 -= go[6] * *cnV[6]; - RHS2 -= go[7] * *cnV[7]; - const double f0 = 1.0 / m_A0; - const double f0_2 = -f0 * m_A4; - m_A6 += m_A1 * f0_2; - RHS2 += f0_2 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_2 = -f1 * m_A5; - m_A6 += m_A3 * f1_2; - RHS2 += f1_2 * RHS1; - V[2] = RHS2 / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[2]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[2]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // brdrline static void nl_gcr_83_double_double_f99b1245e708ec85(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -26154,6 +23273,1582 @@ static void nl_gcr_399_double_double_4334c95878d1be92(double * __restrict V, con V[0] = (RHS0 - tmp0) / m_A0; } +// dribling +static void nl_gcr_21_double_double_c9b5f1625a51d98f(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A2 += gt[7]; + m_A2 += gt[8]; + m_A4 += go[3]; + m_A3 += go[4]; + m_A3 += go[5]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 += Idr[7]; + RHS1 += Idr[8]; + RHS1 -= go[6] * *cnV[6]; + RHS1 -= go[7] * *cnV[7]; + RHS1 -= go[8] * *cnV[8]; + m_A5 += gt[9]; + m_A5 += gt[10]; + m_A5 += gt[11]; + m_A5 += gt[12]; + m_A6 += go[9]; + double RHS2 = Idr[9]; + RHS2 += Idr[10]; + RHS2 += Idr[11]; + RHS2 += Idr[12]; + RHS2 -= go[10] * *cnV[10]; + RHS2 -= go[11] * *cnV[11]; + RHS2 -= go[12] * *cnV[12]; + m_A7 += gt[13]; + m_A7 += gt[14]; + m_A8 += go[13]; + double RHS3 = Idr[13]; + RHS3 += Idr[14]; + RHS3 -= go[14] * *cnV[14]; + m_A11 += gt[15]; + m_A11 += gt[16]; + m_A11 += gt[17]; + m_A11 += gt[18]; + m_A11 += gt[19]; + m_A9 += go[15]; + m_A10 += go[16]; + m_A10 += go[17]; + double RHS4 = Idr[15]; + RHS4 += Idr[16]; + RHS4 += Idr[17]; + RHS4 += Idr[18]; + RHS4 += Idr[19]; + RHS4 -= go[18] * *cnV[18]; + RHS4 -= go[19] * *cnV[19]; + m_A15 += gt[20]; + m_A15 += gt[21]; + m_A16 += go[20]; + m_A13 += go[21]; + double RHS5 = Idr[20]; + RHS5 += Idr[21]; + m_A20 += gt[22]; + m_A20 += gt[23]; + m_A20 += gt[24]; + m_A20 += gt[25]; + m_A20 += gt[26]; + m_A20 += gt[27]; + m_A18 += go[22]; + m_A19 += go[23]; + m_A17 += go[24]; + double RHS6 = Idr[22]; + RHS6 += Idr[23]; + RHS6 += Idr[24]; + RHS6 += Idr[25]; + RHS6 += Idr[26]; + RHS6 += Idr[27]; + RHS6 -= go[25] * *cnV[25]; + RHS6 -= go[26] * *cnV[26]; + RHS6 -= go[27] * *cnV[27]; + const double f0 = 1.0 / m_A0; + const double f0_4 = -f0 * m_A9; + m_A11 += m_A1 * f0_4; + RHS4 += f0_4 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_4 = -f1 * m_A10; + m_A11 += m_A3 * f1_4; + m_A12 += m_A4 * f1_4; + RHS4 += f1_4 * RHS1; + const double f1_5 = -f1 * m_A13; + m_A14 += m_A3 * f1_5; + m_A15 += m_A4 * f1_5; + RHS5 += f1_5 * RHS1; + const double f2 = 1.0 / m_A5; + const double f2_6 = -f2 * m_A17; + m_A20 += m_A6 * f2_6; + RHS6 += f2_6 * RHS2; + const double f3 = 1.0 / m_A7; + const double f3_6 = -f3 * m_A18; + m_A20 += m_A8 * f3_6; + RHS6 += f3_6 * RHS3; + const double f4 = 1.0 / m_A11; + const double f4_5 = -f4 * m_A14; + m_A15 += m_A12 * f4_5; + RHS5 += f4_5 * RHS4; + const double f5 = 1.0 / m_A15; + const double f5_6 = -f5 * m_A19; + m_A20 += m_A16 * f5_6; + RHS6 += f5_6 * RHS5; + V[6] = RHS6 / m_A20; + double tmp5 = 0.0; + tmp5 += m_A16 * V[6]; + V[5] = (RHS5 - tmp5) / m_A15; + double tmp4 = 0.0; + tmp4 += m_A12 * V[5]; + V[4] = (RHS4 - tmp4) / m_A11; + double tmp3 = 0.0; + tmp3 += m_A8 * V[6]; + V[3] = (RHS3 - tmp3) / m_A7; + double tmp2 = 0.0; + tmp2 += m_A6 * V[6]; + V[2] = (RHS2 - tmp2) / m_A5; + double tmp1 = 0.0; + tmp1 += m_A3 * V[4]; + tmp1 += m_A4 * V[5]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[4]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// dribling +static void nl_gcr_28_double_double_99f81817ea8bea2d(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 -= go[4] * *cnV[4]; + RHS1 -= go[5] * *cnV[5]; + m_A4 += gt[6]; + m_A4 += gt[7]; + m_A4 += gt[8]; + m_A5 += go[6]; + double RHS2 = Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 -= go[7] * *cnV[7]; + RHS2 -= go[8] * *cnV[8]; + m_A7 += gt[9]; + m_A7 += gt[10]; + m_A7 += gt[11]; + m_A7 += gt[12]; + m_A7 += gt[13]; + m_A7 += gt[14]; + m_A7 += gt[15]; + m_A6 += go[9]; + m_A8 += go[10]; + double RHS3 = Idr[9]; + RHS3 += Idr[10]; + RHS3 += Idr[11]; + RHS3 += Idr[12]; + RHS3 += Idr[13]; + RHS3 += Idr[14]; + RHS3 += Idr[15]; + RHS3 -= go[11] * *cnV[11]; + RHS3 -= go[12] * *cnV[12]; + RHS3 -= go[13] * *cnV[13]; + RHS3 -= go[14] * *cnV[14]; + RHS3 -= go[15] * *cnV[15]; + m_A9 += gt[16]; + m_A9 += gt[17]; + m_A9 += gt[18]; + m_A10 += go[16]; + double RHS4 = Idr[16]; + RHS4 += Idr[17]; + RHS4 += Idr[18]; + RHS4 -= go[17] * *cnV[17]; + RHS4 -= go[18] * *cnV[18]; + m_A11 += gt[19]; + m_A11 += gt[20]; + m_A12 += go[19]; + double RHS5 = Idr[19]; + RHS5 += Idr[20]; + RHS5 -= go[20] * *cnV[20]; + m_A14 += gt[21]; + m_A14 += gt[22]; + m_A14 += gt[23]; + m_A13 += go[21]; + m_A15 += go[22]; + m_A16 += go[23]; + double RHS6 = Idr[21]; + RHS6 += Idr[22]; + RHS6 += Idr[23]; + m_A19 += gt[24]; + m_A19 += gt[25]; + m_A19 += gt[26]; + m_A19 += gt[27]; + m_A19 += gt[28]; + m_A19 += gt[29]; + m_A17 += go[24]; + m_A18 += go[25]; + m_A20 += go[26]; + double RHS7 = Idr[24]; + RHS7 += Idr[25]; + RHS7 += Idr[26]; + RHS7 += Idr[27]; + RHS7 += Idr[28]; + RHS7 += Idr[29]; + RHS7 -= go[27] * *cnV[27]; + RHS7 -= go[28] * *cnV[28]; + RHS7 -= go[29] * *cnV[29]; + m_A27 += gt[30]; + m_A27 += gt[31]; + m_A27 += gt[32]; + m_A27 += gt[33]; + m_A27 += gt[34]; + m_A27 += gt[35]; + m_A27 += gt[36]; + m_A24 += go[30]; + m_A25 += go[31]; + m_A26 += go[32]; + m_A23 += go[33]; + m_A22 += go[34]; + m_A21 += go[35]; + double RHS8 = Idr[30]; + RHS8 += Idr[31]; + RHS8 += Idr[32]; + RHS8 += Idr[33]; + RHS8 += Idr[34]; + RHS8 += Idr[35]; + RHS8 += Idr[36]; + RHS8 -= go[36] * *cnV[36]; + const double f0 = 1.0 / m_A0; + const double f0_8 = -f0 * m_A21; + m_A27 += m_A1 * f0_8; + RHS8 += f0_8 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_8 = -f1 * m_A22; + m_A27 += m_A3 * f1_8; + RHS8 += f1_8 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_3 = -f2 * m_A6; + m_A8 += m_A5 * f2_3; + RHS3 += f2_3 * RHS2; + const double f2_6 = -f2 * m_A13; + m_A14 += m_A5 * f2_6; + RHS6 += f2_6 * RHS2; + const double f3 = 1.0 / m_A7; + const double f3_7 = -f3 * m_A17; + m_A18 += m_A8 * f3_7; + RHS7 += f3_7 * RHS3; + const double f4 = 1.0 / m_A9; + const double f4_8 = -f4 * m_A23; + m_A27 += m_A10 * f4_8; + RHS8 += f4_8 * RHS4; + const double f5 = 1.0 / m_A11; + const double f5_8 = -f5 * m_A24; + m_A27 += m_A12 * f5_8; + RHS8 += f5_8 * RHS5; + const double f6 = 1.0 / m_A14; + const double f6_7 = -f6 * m_A18; + m_A19 += m_A15 * f6_7; + m_A20 += m_A16 * f6_7; + RHS7 += f6_7 * RHS6; + const double f6_8 = -f6 * m_A25; + m_A26 += m_A15 * f6_8; + m_A27 += m_A16 * f6_8; + RHS8 += f6_8 * RHS6; + const double f7 = 1.0 / m_A19; + const double f7_8 = -f7 * m_A26; + m_A27 += m_A20 * f7_8; + RHS8 += f7_8 * RHS7; + V[8] = RHS8 / m_A27; + double tmp7 = 0.0; + tmp7 += m_A20 * V[8]; + V[7] = (RHS7 - tmp7) / m_A19; + double tmp6 = 0.0; + tmp6 += m_A15 * V[7]; + tmp6 += m_A16 * V[8]; + V[6] = (RHS6 - tmp6) / m_A14; + double tmp5 = 0.0; + tmp5 += m_A12 * V[8]; + V[5] = (RHS5 - tmp5) / m_A11; + double tmp4 = 0.0; + tmp4 += m_A10 * V[8]; + V[4] = (RHS4 - tmp4) / m_A9; + double tmp3 = 0.0; + tmp3 += m_A8 * V[6]; + V[3] = (RHS3 - tmp3) / m_A7; + double tmp2 = 0.0; + tmp2 += m_A5 * V[6]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[8]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[8]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// dribling +static void nl_gcr_29_double_double_1e732268bc2d78b2(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A2 += gt[7]; + m_A2 += gt[8]; + m_A4 += go[3]; + m_A3 += go[4]; + m_A3 += go[5]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 += Idr[7]; + RHS1 += Idr[8]; + RHS1 -= go[6] * *cnV[6]; + RHS1 -= go[7] * *cnV[7]; + RHS1 -= go[8] * *cnV[8]; + m_A5 += gt[9]; + m_A5 += gt[10]; + m_A5 += gt[11]; + m_A5 += gt[12]; + m_A6 += go[9]; + double RHS2 = Idr[9]; + RHS2 += Idr[10]; + RHS2 += Idr[11]; + RHS2 += Idr[12]; + RHS2 -= go[10] * *cnV[10]; + RHS2 -= go[11] * *cnV[11]; + RHS2 -= go[12] * *cnV[12]; + m_A7 += gt[13]; + m_A7 += gt[14]; + m_A7 += gt[15]; + m_A7 += gt[16]; + m_A8 += go[13]; + m_A9 += go[14]; + m_A9 += go[15]; + double RHS3 = Idr[13]; + RHS3 += Idr[14]; + RHS3 += Idr[15]; + RHS3 += Idr[16]; + RHS3 -= go[16] * *cnV[16]; + m_A10 += gt[17]; + m_A10 += gt[18]; + m_A11 += go[17]; + double RHS4 = Idr[17]; + RHS4 += Idr[18]; + RHS4 -= go[18] * *cnV[18]; + m_A14 += gt[19]; + m_A14 += gt[20]; + m_A14 += gt[21]; + m_A14 += gt[22]; + m_A14 += gt[23]; + m_A12 += go[19]; + m_A13 += go[20]; + m_A13 += go[21]; + double RHS5 = Idr[19]; + RHS5 += Idr[20]; + RHS5 += Idr[21]; + RHS5 += Idr[22]; + RHS5 += Idr[23]; + RHS5 -= go[22] * *cnV[22]; + RHS5 -= go[23] * *cnV[23]; + m_A18 += gt[24]; + m_A18 += gt[25]; + m_A19 += go[24]; + m_A16 += go[25]; + double RHS6 = Idr[24]; + RHS6 += Idr[25]; + m_A22 += gt[26]; + m_A22 += gt[27]; + m_A21 += go[26]; + m_A20 += go[27]; + double RHS7 = Idr[26]; + RHS7 += Idr[27]; + m_A28 += gt[28]; + m_A28 += gt[29]; + m_A28 += gt[30]; + m_A28 += gt[31]; + m_A28 += gt[32]; + m_A28 += gt[33]; + m_A28 += gt[34]; + m_A28 += gt[35]; + m_A28 += gt[36]; + m_A28 += gt[37]; + m_A25 += go[28]; + m_A25 += go[29]; + m_A28 += go[30]; + m_A28 += go[31]; + m_A28 += go[32]; + m_A28 += go[33]; + m_A26 += go[34]; + m_A24 += go[35]; + double RHS8 = Idr[28]; + RHS8 += Idr[29]; + RHS8 += Idr[30]; + RHS8 += Idr[31]; + RHS8 += Idr[32]; + RHS8 += Idr[33]; + RHS8 += Idr[34]; + RHS8 += Idr[35]; + RHS8 += Idr[36]; + RHS8 += Idr[37]; + RHS8 -= go[36] * *cnV[36]; + RHS8 -= go[37] * *cnV[37]; + const double f0 = 1.0 / m_A0; + const double f0_5 = -f0 * m_A12; + m_A14 += m_A1 * f0_5; + RHS5 += f0_5 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_5 = -f1 * m_A13; + m_A14 += m_A3 * f1_5; + m_A15 += m_A4 * f1_5; + RHS5 += f1_5 * RHS1; + const double f1_6 = -f1 * m_A16; + m_A17 += m_A3 * f1_6; + m_A18 += m_A4 * f1_6; + RHS6 += f1_6 * RHS1; + const double f2 = 1.0 / m_A5; + const double f2_8 = -f2 * m_A24; + m_A28 += m_A6 * f2_8; + RHS8 += f2_8 * RHS2; + const double f3 = 1.0 / m_A7; + const double f3_7 = -f3 * m_A20; + m_A22 += m_A8 * f3_7; + m_A23 += m_A9 * f3_7; + RHS7 += f3_7 * RHS3; + const double f3_8 = -f3 * m_A25; + m_A27 += m_A8 * f3_8; + m_A28 += m_A9 * f3_8; + RHS8 += f3_8 * RHS3; + const double f4 = 1.0 / m_A10; + const double f4_7 = -f4 * m_A21; + m_A22 += m_A11 * f4_7; + RHS7 += f4_7 * RHS4; + const double f5 = 1.0 / m_A14; + const double f5_6 = -f5 * m_A17; + m_A18 += m_A15 * f5_6; + RHS6 += f5_6 * RHS5; + const double f6 = 1.0 / m_A18; + const double f6_8 = -f6 * m_A26; + m_A28 += m_A19 * f6_8; + RHS8 += f6_8 * RHS6; + const double f7 = 1.0 / m_A22; + const double f7_8 = -f7 * m_A27; + m_A28 += m_A23 * f7_8; + RHS8 += f7_8 * RHS7; + V[8] = RHS8 / m_A28; + double tmp7 = 0.0; + tmp7 += m_A23 * V[8]; + V[7] = (RHS7 - tmp7) / m_A22; + double tmp6 = 0.0; + tmp6 += m_A19 * V[8]; + V[6] = (RHS6 - tmp6) / m_A18; + double tmp5 = 0.0; + tmp5 += m_A15 * V[6]; + V[5] = (RHS5 - tmp5) / m_A14; + double tmp4 = 0.0; + tmp4 += m_A11 * V[7]; + V[4] = (RHS4 - tmp4) / m_A10; + double tmp3 = 0.0; + tmp3 += m_A8 * V[7]; + tmp3 += m_A9 * V[8]; + V[3] = (RHS3 - tmp3) / m_A7; + double tmp2 = 0.0; + tmp2 += m_A6 * V[8]; + V[2] = (RHS2 - tmp2) / m_A5; + double tmp1 = 0.0; + tmp1 += m_A3 * V[5]; + tmp1 += m_A4 * V[6]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[5]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// dribling +static void nl_gcr_54_double_double_a2823a76b83c45a0(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A0 += gt[3]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 += Idr[3]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + RHS0 -= go[3] * *cnV[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A4 += go[4]; + m_A3 += go[5]; + double RHS1 = Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 -= go[6] * *cnV[6]; + m_A5 += gt[7]; + m_A5 += gt[8]; + m_A5 += gt[9]; + m_A5 += gt[10]; + m_A6 += go[7]; + m_A7 += go[8]; + m_A7 += go[9]; + double RHS2 = Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 -= go[10] * *cnV[10]; + m_A8 += gt[11]; + m_A8 += gt[12]; + m_A10 += go[11]; + m_A9 += go[12]; + double RHS3 = Idr[11]; + RHS3 += Idr[12]; + m_A11 += gt[13]; + m_A11 += gt[14]; + m_A11 += gt[15]; + m_A11 += gt[16]; + m_A11 += gt[17]; + m_A13 += go[13]; + m_A12 += go[14]; + m_A12 += go[15]; + double RHS4 = Idr[13]; + RHS4 += Idr[14]; + RHS4 += Idr[15]; + RHS4 += Idr[16]; + RHS4 += Idr[17]; + RHS4 -= go[16] * *cnV[16]; + RHS4 -= go[17] * *cnV[17]; + m_A14 += gt[18]; + m_A14 += gt[19]; + m_A15 += go[18]; + double RHS5 = Idr[18]; + RHS5 += Idr[19]; + RHS5 -= go[19] * *cnV[19]; + m_A17 += gt[20]; + m_A17 += gt[21]; + m_A17 += gt[22]; + m_A19 += go[20]; + m_A18 += go[21]; + m_A16 += go[22]; + double RHS6 = Idr[20]; + RHS6 += Idr[21]; + RHS6 += Idr[22]; + m_A22 += gt[23]; + m_A22 += gt[24]; + m_A22 += gt[25]; + m_A22 += gt[26]; + m_A22 += gt[27]; + m_A22 += gt[28]; + m_A22 += gt[29]; + m_A21 += go[23]; + m_A20 += go[24]; + m_A25 += go[25]; + m_A25 += go[26]; + m_A25 += go[27]; + m_A24 += go[28]; + double RHS7 = Idr[23]; + RHS7 += Idr[24]; + RHS7 += Idr[25]; + RHS7 += Idr[26]; + RHS7 += Idr[27]; + RHS7 += Idr[28]; + RHS7 += Idr[29]; + RHS7 -= go[29] * *cnV[29]; + m_A29 += gt[30]; + m_A29 += gt[31]; + m_A29 += gt[32]; + m_A29 += gt[33]; + m_A29 += gt[34]; + m_A29 += gt[35]; + m_A29 += gt[36]; + m_A32 += go[30]; + m_A32 += go[31]; + m_A27 += go[32]; + m_A27 += go[33]; + m_A26 += go[34]; + double RHS8 = Idr[30]; + RHS8 += Idr[31]; + RHS8 += Idr[32]; + RHS8 += Idr[33]; + RHS8 += Idr[34]; + RHS8 += Idr[35]; + RHS8 += Idr[36]; + RHS8 -= go[35] * *cnV[35]; + RHS8 -= go[36] * *cnV[36]; + m_A37 += gt[37]; + m_A37 += gt[38]; + m_A37 += gt[39]; + m_A35 += go[37]; + m_A33 += go[38]; + m_A34 += go[39]; + double RHS9 = Idr[37]; + RHS9 += Idr[38]; + RHS9 += Idr[39]; + m_A46 += gt[40]; + m_A46 += gt[41]; + m_A46 += gt[42]; + m_A46 += gt[43]; + m_A46 += gt[44]; + m_A46 += gt[45]; + m_A46 += gt[46]; + m_A41 += go[40]; + m_A41 += go[41]; + m_A43 += go[42]; + m_A43 += go[43]; + m_A43 += go[44]; + m_A40 += go[45]; + m_A42 += go[46]; + double RHS10 = Idr[40]; + RHS10 += Idr[41]; + RHS10 += Idr[42]; + RHS10 += Idr[43]; + RHS10 += Idr[44]; + RHS10 += Idr[45]; + RHS10 += Idr[46]; + m_A53 += gt[47]; + m_A53 += gt[48]; + m_A53 += gt[49]; + m_A53 += gt[50]; + m_A53 += gt[51]; + m_A49 += go[47]; + m_A48 += go[48]; + m_A50 += go[49]; + m_A50 += go[50]; + double RHS11 = Idr[47]; + RHS11 += Idr[48]; + RHS11 += Idr[49]; + RHS11 += Idr[50]; + RHS11 += Idr[51]; + RHS11 -= go[51] * *cnV[51]; + const double f0 = 1.0 / m_A0; + const double f0_6 = -f0 * m_A16; + m_A17 += m_A1 * f0_6; + RHS6 += f0_6 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_9 = -f1 * m_A33; + m_A37 += m_A3 * f1_9; + m_A38 += m_A4 * f1_9; + RHS9 += f1_9 * RHS1; + const double f1_10 = -f1 * m_A40; + m_A45 += m_A3 * f1_10; + m_A46 += m_A4 * f1_10; + RHS10 += f1_10 * RHS1; + const double f2 = 1.0 / m_A5; + const double f2_7 = -f2 * m_A20; + m_A22 += m_A6 * f2_7; + m_A25 += m_A7 * f2_7; + RHS7 += f2_7 * RHS2; + const double f2_10 = -f2 * m_A41; + m_A43 += m_A6 * f2_10; + m_A46 += m_A7 * f2_10; + RHS10 += f2_10 * RHS2; + const double f3 = 1.0 / m_A8; + const double f3_7 = -f3 * m_A21; + m_A22 += m_A9 * f3_7; + m_A23 += m_A10 * f3_7; + RHS7 += f3_7 * RHS3; + const double f3_8 = -f3 * m_A26; + m_A28 += m_A9 * f3_8; + m_A29 += m_A10 * f3_8; + RHS8 += f3_8 * RHS3; + const double f4 = 1.0 / m_A11; + const double f4_8 = -f4 * m_A27; + m_A29 += m_A12 * f4_8; + m_A32 += m_A13 * f4_8; + RHS8 += f4_8 * RHS4; + const double f4_11 = -f4 * m_A48; + m_A50 += m_A12 * f4_11; + m_A53 += m_A13 * f4_11; + RHS11 += f4_11 * RHS4; + const double f5 = 1.0 / m_A14; + const double f5_11 = -f5 * m_A49; + m_A53 += m_A15 * f5_11; + RHS11 += f5_11 * RHS5; + const double f6 = 1.0 / m_A17; + const double f6_9 = -f6 * m_A34; + m_A37 += m_A18 * f6_9; + m_A38 += m_A19 * f6_9; + RHS9 += f6_9 * RHS6; + const double f6_10 = -f6 * m_A42; + m_A45 += m_A18 * f6_10; + m_A46 += m_A19 * f6_10; + RHS10 += f6_10 * RHS6; + const double f7 = 1.0 / m_A22; + const double f7_8 = -f7 * m_A28; + m_A29 += m_A23 * f7_8; + m_A30 += m_A24 * f7_8; + m_A31 += m_A25 * f7_8; + RHS8 += f7_8 * RHS7; + const double f7_9 = -f7 * m_A35; + m_A36 += m_A23 * f7_9; + m_A37 += m_A24 * f7_9; + m_A38 += m_A25 * f7_9; + RHS9 += f7_9 * RHS7; + const double f7_10 = -f7 * m_A43; + m_A44 += m_A23 * f7_10; + m_A45 += m_A24 * f7_10; + m_A46 += m_A25 * f7_10; + RHS10 += f7_10 * RHS7; + const double f8 = 1.0 / m_A29; + const double f8_9 = -f8 * m_A36; + m_A37 += m_A30 * f8_9; + m_A38 += m_A31 * f8_9; + m_A39 += m_A32 * f8_9; + RHS9 += f8_9 * RHS8; + const double f8_10 = -f8 * m_A44; + m_A45 += m_A30 * f8_10; + m_A46 += m_A31 * f8_10; + m_A47 += m_A32 * f8_10; + RHS10 += f8_10 * RHS8; + const double f8_11 = -f8 * m_A50; + m_A51 += m_A30 * f8_11; + m_A52 += m_A31 * f8_11; + m_A53 += m_A32 * f8_11; + RHS11 += f8_11 * RHS8; + const double f9 = 1.0 / m_A37; + const double f9_10 = -f9 * m_A45; + m_A46 += m_A38 * f9_10; + m_A47 += m_A39 * f9_10; + RHS10 += f9_10 * RHS9; + const double f9_11 = -f9 * m_A51; + m_A52 += m_A38 * f9_11; + m_A53 += m_A39 * f9_11; + RHS11 += f9_11 * RHS9; + const double f10 = 1.0 / m_A46; + const double f10_11 = -f10 * m_A52; + m_A53 += m_A47 * f10_11; + RHS11 += f10_11 * RHS10; + V[11] = RHS11 / m_A53; + double tmp10 = 0.0; + tmp10 += m_A47 * V[11]; + V[10] = (RHS10 - tmp10) / m_A46; + double tmp9 = 0.0; + tmp9 += m_A38 * V[10]; + tmp9 += m_A39 * V[11]; + V[9] = (RHS9 - tmp9) / m_A37; + double tmp8 = 0.0; + tmp8 += m_A30 * V[9]; + tmp8 += m_A31 * V[10]; + tmp8 += m_A32 * V[11]; + V[8] = (RHS8 - tmp8) / m_A29; + double tmp7 = 0.0; + tmp7 += m_A23 * V[8]; + tmp7 += m_A24 * V[9]; + tmp7 += m_A25 * V[10]; + V[7] = (RHS7 - tmp7) / m_A22; + double tmp6 = 0.0; + tmp6 += m_A18 * V[9]; + tmp6 += m_A19 * V[10]; + V[6] = (RHS6 - tmp6) / m_A17; + double tmp5 = 0.0; + tmp5 += m_A15 * V[11]; + V[5] = (RHS5 - tmp5) / m_A14; + double tmp4 = 0.0; + tmp4 += m_A12 * V[8]; + tmp4 += m_A13 * V[11]; + V[4] = (RHS4 - tmp4) / m_A11; + double tmp3 = 0.0; + tmp3 += m_A9 * V[7]; + tmp3 += m_A10 * V[8]; + V[3] = (RHS3 - tmp3) / m_A8; + double tmp2 = 0.0; + tmp2 += m_A6 * V[7]; + tmp2 += m_A7 * V[10]; + V[2] = (RHS2 - tmp2) / m_A5; + double tmp1 = 0.0; + tmp1 += m_A3 * V[9]; + tmp1 += m_A4 * V[10]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[6]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// dribling +static void nl_gcr_7_double_double_a1ecff4d37b54b76(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A0 += gt[3]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 += Idr[3]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + RHS0 -= go[3] * *cnV[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A3 += go[4]; + double RHS1 = Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 -= go[5] * *cnV[5]; + RHS1 -= go[6] * *cnV[6]; + m_A6 += gt[7]; + m_A6 += gt[8]; + m_A6 += gt[9]; + m_A5 += go[7]; + m_A4 += go[8]; + double RHS2 = Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 -= go[9] * *cnV[9]; + const double f0 = 1.0 / m_A0; + const double f0_2 = -f0 * m_A4; + m_A6 += m_A1 * f0_2; + RHS2 += f0_2 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + RHS2 += f1_2 * RHS1; + V[2] = RHS2 / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[2]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// dribling +static void nl_gcr_95_double_double_a0159c41cfc0b644(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + double m_A54(0.0); + double m_A55(0.0); + double m_A56(0.0); + double m_A57(0.0); + double m_A58(0.0); + double m_A59(0.0); + double m_A60(0.0); + double m_A61(0.0); + double m_A62(0.0); + double m_A63(0.0); + double m_A64(0.0); + double m_A65(0.0); + double m_A66(0.0); + double m_A67(0.0); + double m_A68(0.0); + double m_A69(0.0); + double m_A70(0.0); + double m_A71(0.0); + double m_A72(0.0); + double m_A73(0.0); + double m_A74(0.0); + double m_A75(0.0); + double m_A76(0.0); + double m_A77(0.0); + double m_A78(0.0); + double m_A79(0.0); + double m_A80(0.0); + double m_A81(0.0); + double m_A82(0.0); + double m_A83(0.0); + double m_A84(0.0); + double m_A85(0.0); + double m_A86(0.0); + double m_A87(0.0); + double m_A88(0.0); + double m_A89(0.0); + double m_A90(0.0); + double m_A91(0.0); + double m_A92(0.0); + double m_A93(0.0); + double m_A94(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A3 += go[2]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 -= go[3] * *cnV[3]; + m_A4 += gt[4]; + m_A4 += gt[5]; + m_A5 += go[4]; + double RHS2 = Idr[4]; + RHS2 += Idr[5]; + RHS2 -= go[5] * *cnV[5]; + m_A6 += gt[6]; + m_A6 += gt[7]; + m_A7 += go[6]; + double RHS3 = Idr[6]; + RHS3 += Idr[7]; + RHS3 -= go[7] * *cnV[7]; + m_A8 += gt[8]; + m_A8 += gt[9]; + m_A9 += go[8]; + double RHS4 = Idr[8]; + RHS4 += Idr[9]; + RHS4 -= go[9] * *cnV[9]; + m_A10 += gt[10]; + m_A10 += gt[11]; + m_A11 += go[10]; + double RHS5 = Idr[10]; + RHS5 += Idr[11]; + RHS5 -= go[11] * *cnV[11]; + m_A12 += gt[12]; + m_A12 += gt[13]; + m_A12 += gt[14]; + m_A13 += go[12]; + double RHS6 = Idr[12]; + RHS6 += Idr[13]; + RHS6 += Idr[14]; + RHS6 -= go[13] * *cnV[13]; + RHS6 -= go[14] * *cnV[14]; + m_A14 += gt[15]; + m_A14 += gt[16]; + m_A14 += gt[17]; + m_A14 += gt[18]; + m_A15 += go[15]; + double RHS7 = Idr[15]; + RHS7 += Idr[16]; + RHS7 += Idr[17]; + RHS7 += Idr[18]; + RHS7 -= go[16] * *cnV[16]; + RHS7 -= go[17] * *cnV[17]; + RHS7 -= go[18] * *cnV[18]; + m_A16 += gt[19]; + m_A16 += gt[20]; + m_A18 += go[19]; + m_A17 += go[20]; + double RHS8 = Idr[19]; + RHS8 += Idr[20]; + m_A19 += gt[21]; + m_A19 += gt[22]; + m_A21 += go[21]; + m_A20 += go[22]; + double RHS9 = Idr[21]; + RHS9 += Idr[22]; + m_A22 += gt[23]; + m_A22 += gt[24]; + m_A24 += go[23]; + m_A23 += go[24]; + double RHS10 = Idr[23]; + RHS10 += Idr[24]; + m_A25 += gt[25]; + m_A25 += gt[26]; + m_A27 += go[25]; + m_A26 += go[26]; + double RHS11 = Idr[25]; + RHS11 += Idr[26]; + m_A28 += gt[27]; + m_A28 += gt[28]; + m_A28 += gt[29]; + m_A30 += go[27]; + m_A29 += go[28]; + m_A31 += go[29]; + double RHS12 = Idr[27]; + RHS12 += Idr[28]; + RHS12 += Idr[29]; + m_A32 += gt[30]; + m_A32 += gt[31]; + m_A34 += go[30]; + m_A33 += go[31]; + double RHS13 = Idr[30]; + RHS13 += Idr[31]; + m_A36 += gt[32]; + m_A36 += gt[33]; + m_A37 += go[32]; + m_A35 += go[33]; + double RHS14 = Idr[32]; + RHS14 += Idr[33]; + m_A39 += gt[34]; + m_A39 += gt[35]; + m_A40 += go[34]; + m_A38 += go[35]; + double RHS15 = Idr[34]; + RHS15 += Idr[35]; + m_A43 += gt[36]; + m_A43 += gt[37]; + m_A42 += go[36]; + m_A41 += go[37]; + double RHS16 = Idr[36]; + RHS16 += Idr[37]; + m_A47 += gt[38]; + m_A47 += gt[39]; + m_A46 += go[38]; + m_A45 += go[39]; + double RHS17 = Idr[38]; + RHS17 += Idr[39]; + m_A51 += gt[40]; + m_A51 += gt[41]; + m_A50 += go[40]; + m_A49 += go[41]; + double RHS18 = Idr[40]; + RHS18 += Idr[41]; + m_A55 += gt[42]; + m_A55 += gt[43]; + m_A54 += go[42]; + m_A53 += go[43]; + double RHS19 = Idr[42]; + RHS19 += Idr[43]; + m_A58 += gt[44]; + m_A58 += gt[45]; + m_A58 += gt[46]; + m_A59 += go[44]; + m_A57 += go[45]; + double RHS20 = Idr[44]; + RHS20 += Idr[45]; + RHS20 += Idr[46]; + RHS20 -= go[46] * *cnV[46]; + m_A62 += gt[47]; + m_A62 += gt[48]; + m_A62 += gt[49]; + m_A62 += gt[50]; + m_A62 += gt[51]; + m_A63 += go[47]; + m_A63 += go[48]; + m_A61 += go[49]; + double RHS21 = Idr[47]; + RHS21 += Idr[48]; + RHS21 += Idr[49]; + RHS21 += Idr[50]; + RHS21 += Idr[51]; + RHS21 -= go[50] * *cnV[50]; + RHS21 -= go[51] * *cnV[51]; + m_A66 += gt[52]; + m_A66 += gt[53]; + m_A65 += go[52]; + m_A64 += go[53]; + double RHS22 = Idr[52]; + RHS22 += Idr[53]; + m_A70 += gt[54]; + m_A70 += gt[55]; + m_A70 += gt[56]; + m_A70 += gt[57]; + m_A70 += gt[58]; + m_A70 += go[54]; + m_A69 += go[55]; + m_A69 += go[56]; + m_A68 += go[57]; + double RHS23 = Idr[54]; + RHS23 += Idr[55]; + RHS23 += Idr[56]; + RHS23 += Idr[57]; + RHS23 += Idr[58]; + RHS23 -= go[58] * *cnV[58]; + m_A75 += gt[59]; + m_A75 += gt[60]; + m_A75 += gt[61]; + m_A72 += go[59]; + m_A76 += go[60]; + double RHS24 = Idr[59]; + RHS24 += Idr[60]; + RHS24 += Idr[61]; + RHS24 -= go[61] * *cnV[61]; + m_A78 += gt[62]; + m_A78 += gt[63]; + m_A79 += go[62]; + m_A77 += go[63]; + double RHS25 = Idr[62]; + RHS25 += Idr[63]; + m_A94 += gt[64]; + m_A94 += gt[65]; + m_A94 += gt[66]; + m_A94 += gt[67]; + m_A94 += gt[68]; + m_A94 += gt[69]; + m_A94 += gt[70]; + m_A94 += gt[71]; + m_A94 += gt[72]; + m_A94 += gt[73]; + m_A94 += gt[74]; + m_A92 += go[64]; + m_A90 += go[65]; + m_A90 += go[66]; + m_A93 += go[67]; + m_A84 += go[68]; + m_A83 += go[69]; + m_A82 += go[70]; + m_A81 += go[71]; + m_A80 += go[72]; + m_A85 += go[73]; + double RHS26 = Idr[64]; + RHS26 += Idr[65]; + RHS26 += Idr[66]; + RHS26 += Idr[67]; + RHS26 += Idr[68]; + RHS26 += Idr[69]; + RHS26 += Idr[70]; + RHS26 += Idr[71]; + RHS26 += Idr[72]; + RHS26 += Idr[73]; + RHS26 += Idr[74]; + RHS26 -= go[74] * *cnV[74]; + const double f0 = 1.0 / m_A0; + const double f0_16 = -f0 * m_A41; + m_A43 += m_A1 * f0_16; + RHS16 += f0_16 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_17 = -f1 * m_A45; + m_A47 += m_A3 * f1_17; + RHS17 += f1_17 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_18 = -f2 * m_A49; + m_A51 += m_A5 * f2_18; + RHS18 += f2_18 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_19 = -f3 * m_A53; + m_A55 += m_A7 * f3_19; + RHS19 += f3_19 * RHS3; + const double f4 = 1.0 / m_A8; + const double f4_22 = -f4 * m_A64; + m_A66 += m_A9 * f4_22; + RHS22 += f4_22 * RHS4; + const double f5 = 1.0 / m_A10; + const double f5_14 = -f5 * m_A35; + m_A36 += m_A11 * f5_14; + RHS14 += f5_14 * RHS5; + const double f6 = 1.0 / m_A12; + const double f6_15 = -f6 * m_A38; + m_A39 += m_A13 * f6_15; + RHS15 += f6_15 * RHS6; + const double f7 = 1.0 / m_A14; + const double f7_21 = -f7 * m_A61; + m_A62 += m_A15 * f7_21; + RHS21 += f7_21 * RHS7; + const double f8 = 1.0 / m_A16; + const double f8_16 = -f8 * m_A42; + m_A43 += m_A17 * f8_16; + m_A44 += m_A18 * f8_16; + RHS16 += f8_16 * RHS8; + const double f8_26 = -f8 * m_A80; + m_A86 += m_A17 * f8_26; + m_A94 += m_A18 * f8_26; + RHS26 += f8_26 * RHS8; + const double f9 = 1.0 / m_A19; + const double f9_17 = -f9 * m_A46; + m_A47 += m_A20 * f9_17; + m_A48 += m_A21 * f9_17; + RHS17 += f9_17 * RHS9; + const double f9_26 = -f9 * m_A81; + m_A87 += m_A20 * f9_26; + m_A94 += m_A21 * f9_26; + RHS26 += f9_26 * RHS9; + const double f10 = 1.0 / m_A22; + const double f10_18 = -f10 * m_A50; + m_A51 += m_A23 * f10_18; + m_A52 += m_A24 * f10_18; + RHS18 += f10_18 * RHS10; + const double f10_26 = -f10 * m_A82; + m_A88 += m_A23 * f10_26; + m_A94 += m_A24 * f10_26; + RHS26 += f10_26 * RHS10; + const double f11 = 1.0 / m_A25; + const double f11_19 = -f11 * m_A54; + m_A55 += m_A26 * f11_19; + m_A56 += m_A27 * f11_19; + RHS19 += f11_19 * RHS11; + const double f11_26 = -f11 * m_A83; + m_A89 += m_A26 * f11_26; + m_A94 += m_A27 * f11_26; + RHS26 += f11_26 * RHS11; + const double f12 = 1.0 / m_A28; + const double f12_20 = -f12 * m_A57; + m_A58 += m_A29 * f12_20; + m_A59 += m_A30 * f12_20; + m_A60 += m_A31 * f12_20; + RHS20 += f12_20 * RHS12; + const double f12_23 = -f12 * m_A68; + m_A69 += m_A29 * f12_23; + m_A70 += m_A30 * f12_23; + m_A71 += m_A31 * f12_23; + RHS23 += f12_23 * RHS12; + const double f12_24 = -f12 * m_A72; + m_A73 += m_A29 * f12_24; + m_A74 += m_A30 * f12_24; + m_A75 += m_A31 * f12_24; + RHS24 += f12_24 * RHS12; + const double f13 = 1.0 / m_A32; + const double f13_22 = -f13 * m_A65; + m_A66 += m_A33 * f13_22; + m_A67 += m_A34 * f13_22; + RHS22 += f13_22 * RHS13; + const double f13_26 = -f13 * m_A84; + m_A91 += m_A33 * f13_26; + m_A94 += m_A34 * f13_26; + RHS26 += f13_26 * RHS13; + const double f14 = 1.0 / m_A36; + const double f14_25 = -f14 * m_A77; + m_A78 += m_A37 * f14_25; + RHS25 += f14_25 * RHS14; + const double f15 = 1.0 / m_A39; + const double f15_26 = -f15 * m_A85; + m_A94 += m_A40 * f15_26; + RHS26 += f15_26 * RHS15; + const double f16 = 1.0 / m_A43; + const double f16_26 = -f16 * m_A86; + m_A94 += m_A44 * f16_26; + RHS26 += f16_26 * RHS16; + const double f17 = 1.0 / m_A47; + const double f17_26 = -f17 * m_A87; + m_A94 += m_A48 * f17_26; + RHS26 += f17_26 * RHS17; + const double f18 = 1.0 / m_A51; + const double f18_26 = -f18 * m_A88; + m_A94 += m_A52 * f18_26; + RHS26 += f18_26 * RHS18; + const double f19 = 1.0 / m_A55; + const double f19_26 = -f19 * m_A89; + m_A94 += m_A56 * f19_26; + RHS26 += f19_26 * RHS19; + const double f20 = 1.0 / m_A58; + const double f20_23 = -f20 * m_A69; + m_A70 += m_A59 * f20_23; + m_A71 += m_A60 * f20_23; + RHS23 += f20_23 * RHS20; + const double f20_24 = -f20 * m_A73; + m_A74 += m_A59 * f20_24; + m_A75 += m_A60 * f20_24; + RHS24 += f20_24 * RHS20; + const double f21 = 1.0 / m_A62; + const double f21_26 = -f21 * m_A90; + m_A94 += m_A63 * f21_26; + RHS26 += f21_26 * RHS21; + const double f22 = 1.0 / m_A66; + const double f22_26 = -f22 * m_A91; + m_A94 += m_A67 * f22_26; + RHS26 += f22_26 * RHS22; + const double f23 = 1.0 / m_A70; + const double f23_24 = -f23 * m_A74; + m_A75 += m_A71 * f23_24; + RHS24 += f23_24 * RHS23; + const double f24 = 1.0 / m_A75; + const double f24_26 = -f24 * m_A92; + m_A94 += m_A76 * f24_26; + RHS26 += f24_26 * RHS24; + const double f25 = 1.0 / m_A78; + const double f25_26 = -f25 * m_A93; + m_A94 += m_A79 * f25_26; + RHS26 += f25_26 * RHS25; + V[26] = RHS26 / m_A94; + double tmp25 = 0.0; + tmp25 += m_A79 * V[26]; + V[25] = (RHS25 - tmp25) / m_A78; + double tmp24 = 0.0; + tmp24 += m_A76 * V[26]; + V[24] = (RHS24 - tmp24) / m_A75; + double tmp23 = 0.0; + tmp23 += m_A71 * V[24]; + V[23] = (RHS23 - tmp23) / m_A70; + double tmp22 = 0.0; + tmp22 += m_A67 * V[26]; + V[22] = (RHS22 - tmp22) / m_A66; + double tmp21 = 0.0; + tmp21 += m_A63 * V[26]; + V[21] = (RHS21 - tmp21) / m_A62; + double tmp20 = 0.0; + tmp20 += m_A59 * V[23]; + tmp20 += m_A60 * V[24]; + V[20] = (RHS20 - tmp20) / m_A58; + double tmp19 = 0.0; + tmp19 += m_A56 * V[26]; + V[19] = (RHS19 - tmp19) / m_A55; + double tmp18 = 0.0; + tmp18 += m_A52 * V[26]; + V[18] = (RHS18 - tmp18) / m_A51; + double tmp17 = 0.0; + tmp17 += m_A48 * V[26]; + V[17] = (RHS17 - tmp17) / m_A47; + double tmp16 = 0.0; + tmp16 += m_A44 * V[26]; + V[16] = (RHS16 - tmp16) / m_A43; + double tmp15 = 0.0; + tmp15 += m_A40 * V[26]; + V[15] = (RHS15 - tmp15) / m_A39; + double tmp14 = 0.0; + tmp14 += m_A37 * V[25]; + V[14] = (RHS14 - tmp14) / m_A36; + double tmp13 = 0.0; + tmp13 += m_A33 * V[22]; + tmp13 += m_A34 * V[26]; + V[13] = (RHS13 - tmp13) / m_A32; + double tmp12 = 0.0; + tmp12 += m_A29 * V[20]; + tmp12 += m_A30 * V[23]; + tmp12 += m_A31 * V[24]; + V[12] = (RHS12 - tmp12) / m_A28; + double tmp11 = 0.0; + tmp11 += m_A26 * V[19]; + tmp11 += m_A27 * V[26]; + V[11] = (RHS11 - tmp11) / m_A25; + double tmp10 = 0.0; + tmp10 += m_A23 * V[18]; + tmp10 += m_A24 * V[26]; + V[10] = (RHS10 - tmp10) / m_A22; + double tmp9 = 0.0; + tmp9 += m_A20 * V[17]; + tmp9 += m_A21 * V[26]; + V[9] = (RHS9 - tmp9) / m_A19; + double tmp8 = 0.0; + tmp8 += m_A17 * V[16]; + tmp8 += m_A18 * V[26]; + V[8] = (RHS8 - tmp8) / m_A16; + double tmp7 = 0.0; + tmp7 += m_A15 * V[21]; + V[7] = (RHS7 - tmp7) / m_A14; + double tmp6 = 0.0; + tmp6 += m_A13 * V[15]; + V[6] = (RHS6 - tmp6) / m_A12; + double tmp5 = 0.0; + tmp5 += m_A11 * V[14]; + V[5] = (RHS5 - tmp5) / m_A10; + double tmp4 = 0.0; + tmp4 += m_A9 * V[22]; + V[4] = (RHS4 - tmp4) / m_A8; + double tmp3 = 0.0; + tmp3 += m_A7 * V[19]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[18]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[17]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[16]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // elim,zektor static void nl_gcr_10_double_double_11c2ae166b240b6e(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -28709,57 +27404,6 @@ static void nl_gcr_45_double_double_28b736fe552777a9(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// elim,zektor -static void nl_gcr_7_double_double_d190a0e3b8e1f4a7(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A3 += go[2]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 -= go[3] * *cnV[3]; - m_A6 += gt[4]; - m_A6 += gt[5]; - m_A6 += gt[6]; - m_A5 += go[4]; - m_A4 += go[5]; - double RHS2 = Idr[4]; - RHS2 += Idr[5]; - RHS2 += Idr[6]; - RHS2 -= go[6] * *cnV[6]; - const double f0 = 1.0 / m_A0; - const double f0_2 = -f0 * m_A4; - m_A6 += m_A1 * f0_2; - RHS2 += f0_2 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_2 = -f1 * m_A5; - m_A6 += m_A3 * f1_2; - RHS2 += f1_2 * RHS1; - V[2] = RHS2 / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[2]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[2]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // fireone static void nl_gcr_128_double_double_7aee4423e3fdbfda(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -33183,63 +31827,6 @@ static void nl_gcr_79_double_double_c1d22fe6e895255d(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// fireone,astrob,rebound,speedfrk,cheekyms -static void nl_gcr_7_double_double_7c86a9bc1c6aef4c(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A0 += gt[2]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 += Idr[2]; - RHS0 -= go[1] * *cnV[1]; - RHS0 -= go[2] * *cnV[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A3 += go[3]; - double RHS1 = Idr[3]; - RHS1 += Idr[4]; - RHS1 -= go[4] * *cnV[4]; - m_A6 += gt[5]; - m_A6 += gt[6]; - m_A6 += gt[7]; - m_A6 += gt[8]; - m_A5 += go[5]; - m_A4 += go[6]; - double RHS2 = Idr[5]; - RHS2 += Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 -= go[7] * *cnV[7]; - RHS2 -= go[8] * *cnV[8]; - const double f0 = 1.0 / m_A0; - const double f0_2 = -f0 * m_A4; - m_A6 += m_A1 * f0_2; - RHS2 += f0_2 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_2 = -f1 * m_A5; - m_A6 += m_A3 * f1_2; - RHS2 += f1_2 * RHS1; - V[2] = RHS2 / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[2]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[2]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // fireone static void nl_gcr_7_double_double_e7fb484f621b3ab9(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -38153,8 +36740,163 @@ static void nl_gcr_7_double_double_782d79b5cbe953b1(double * __restrict V, const V[0] = (RHS0 - tmp0) / m_A0; } +// gi6809 +static void nl_gcr_13_double_double_9eda6de0d275a3e5(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 -= go[4] * *cnV[4]; + RHS1 -= go[5] * *cnV[5]; + RHS1 -= go[6] * *cnV[6]; + m_A4 += gt[7]; + m_A4 += gt[8]; + m_A4 += gt[9]; + m_A4 += gt[10]; + m_A5 += go[7]; + double RHS2 = Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 -= go[8] * *cnV[8]; + RHS2 -= go[9] * *cnV[9]; + RHS2 -= go[10] * *cnV[10]; + m_A6 += gt[11]; + m_A6 += gt[12]; + m_A7 += go[11]; + double RHS3 = Idr[11]; + RHS3 += Idr[12]; + RHS3 -= go[12] * *cnV[12]; + m_A12 += gt[13]; + m_A12 += gt[14]; + m_A12 += gt[15]; + m_A12 += gt[16]; + m_A12 += gt[17]; + m_A12 += gt[18]; + m_A11 += go[13]; + m_A10 += go[14]; + m_A9 += go[15]; + m_A8 += go[16]; + double RHS4 = Idr[13]; + RHS4 += Idr[14]; + RHS4 += Idr[15]; + RHS4 += Idr[16]; + RHS4 += Idr[17]; + RHS4 += Idr[18]; + RHS4 -= go[17] * *cnV[17]; + RHS4 -= go[18] * *cnV[18]; + const double f0 = 1.0 / m_A0; + const double f0_4 = -f0 * m_A8; + m_A12 += m_A1 * f0_4; + RHS4 += f0_4 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_4 = -f1 * m_A9; + m_A12 += m_A3 * f1_4; + RHS4 += f1_4 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_4 = -f2 * m_A10; + m_A12 += m_A5 * f2_4; + RHS4 += f2_4 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_4 = -f3 * m_A11; + m_A12 += m_A7 * f3_4; + RHS4 += f3_4 * RHS3; + V[4] = RHS4 / m_A12; + double tmp3 = 0.0; + tmp3 += m_A7 * V[4]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[4]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[4]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[4]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// gi6809 +static void nl_gcr_7_double_double_8a409a18e77784cb(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A3 += go[2]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 -= go[3] * *cnV[3]; + m_A6 += gt[4]; + m_A6 += gt[5]; + m_A5 += go[4]; + m_A4 += go[5]; + double RHS2 = Idr[4]; + RHS2 += Idr[5]; + const double f0 = 1.0 / m_A0; + const double f0_2 = -f0 * m_A4; + m_A6 += m_A1 * f0_2; + RHS2 += f0_2 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + RHS2 += f1_2 * RHS1; + V[2] = RHS2 / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[2]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // gtrak10 -static void nl_gcr_43_double_double_4c46fdf7c0037727(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) +static void nl_gcr_22_double_double_1f38df4919cdddae(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) { @@ -38181,27 +36923,6 @@ static void nl_gcr_43_double_double_4c46fdf7c0037727(double * __restrict V, cons double m_A19(0.0); double m_A20(0.0); double m_A21(0.0); - double m_A22(0.0); - double m_A23(0.0); - double m_A24(0.0); - double m_A25(0.0); - double m_A26(0.0); - double m_A27(0.0); - double m_A28(0.0); - double m_A29(0.0); - double m_A30(0.0); - double m_A31(0.0); - double m_A32(0.0); - double m_A33(0.0); - double m_A34(0.0); - double m_A35(0.0); - double m_A36(0.0); - double m_A37(0.0); - double m_A38(0.0); - double m_A39(0.0); - double m_A40(0.0); - double m_A41(0.0); - double m_A42(0.0); m_A0 += gt[0]; m_A0 += gt[1]; m_A0 += gt[2]; @@ -38221,262 +36942,159 @@ static void nl_gcr_43_double_double_4c46fdf7c0037727(double * __restrict V, cons RHS1 -= go[4] * *cnV[4]; RHS1 -= go[5] * *cnV[5]; m_A4 += gt[6]; - m_A4 += gt[7]; - m_A4 += gt[8]; m_A5 += go[6]; double RHS2 = Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 -= go[7] * *cnV[7]; - RHS2 -= go[8] * *cnV[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A6 += gt[11]; - m_A7 += go[9]; - double RHS3 = Idr[9]; - RHS3 += Idr[10]; - RHS3 += Idr[11]; - RHS3 -= go[10] * *cnV[10]; - RHS3 -= go[11] * *cnV[11]; - m_A8 += gt[12]; - m_A8 += gt[13]; - m_A8 += gt[14]; - m_A9 += go[12]; - double RHS4 = Idr[12]; - RHS4 += Idr[13]; - RHS4 += Idr[14]; - RHS4 -= go[13] * *cnV[13]; - RHS4 -= go[14] * *cnV[14]; - m_A10 += gt[15]; - m_A10 += gt[16]; - m_A10 += gt[17]; - m_A11 += go[15]; - double RHS5 = Idr[15]; - RHS5 += Idr[16]; - RHS5 += Idr[17]; - RHS5 -= go[16] * *cnV[16]; - RHS5 -= go[17] * *cnV[17]; - m_A12 += gt[18]; - m_A12 += gt[19]; - m_A12 += gt[20]; - m_A13 += go[18]; - double RHS6 = Idr[18]; - RHS6 += Idr[19]; - RHS6 += Idr[20]; - RHS6 -= go[19] * *cnV[19]; - RHS6 -= go[20] * *cnV[20]; - m_A14 += gt[21]; - m_A14 += gt[22]; - m_A14 += gt[23]; - m_A15 += go[21]; - double RHS7 = Idr[21]; + m_A6 += gt[7]; + m_A7 += go[7]; + double RHS3 = Idr[7]; + m_A8 += gt[8]; + m_A8 += gt[9]; + m_A8 += gt[10]; + m_A9 += go[8]; + double RHS4 = Idr[8]; + RHS4 += Idr[9]; + RHS4 += Idr[10]; + RHS4 -= go[9] * *cnV[9]; + RHS4 -= go[10] * *cnV[10]; + m_A10 += gt[11]; + m_A10 += gt[12]; + m_A10 += gt[13]; + m_A11 += go[11]; + double RHS5 = Idr[11]; + RHS5 += Idr[12]; + RHS5 += Idr[13]; + RHS5 -= go[12] * *cnV[12]; + RHS5 -= go[13] * *cnV[13]; + m_A14 += gt[14]; + m_A14 += gt[15]; + m_A14 += gt[16]; + m_A13 += go[14]; + m_A12 += go[15]; + m_A15 += go[16]; + double RHS6 = Idr[14]; + RHS6 += Idr[15]; + RHS6 += Idr[16]; + m_A21 += gt[17]; + m_A21 += gt[18]; + m_A21 += gt[19]; + m_A21 += gt[20]; + m_A21 += gt[21]; + m_A21 += gt[22]; + m_A21 += gt[23]; + m_A20 += go[17]; + m_A19 += go[18]; + m_A18 += go[19]; + m_A17 += go[20]; + m_A16 += go[21]; + double RHS7 = Idr[17]; + RHS7 += Idr[18]; + RHS7 += Idr[19]; + RHS7 += Idr[20]; + RHS7 += Idr[21]; RHS7 += Idr[22]; RHS7 += Idr[23]; RHS7 -= go[22] * *cnV[22]; RHS7 -= go[23] * *cnV[23]; - m_A16 += gt[24]; - m_A16 += gt[25]; - m_A16 += gt[26]; - m_A17 += go[24]; - double RHS8 = Idr[24]; - RHS8 += Idr[25]; - RHS8 += Idr[26]; - RHS8 -= go[25] * *cnV[25]; - RHS8 -= go[26] * *cnV[26]; - m_A18 += gt[27]; - m_A18 += gt[28]; - m_A18 += gt[29]; - m_A19 += go[27]; - double RHS9 = Idr[27]; - RHS9 += Idr[28]; - RHS9 += Idr[29]; - RHS9 -= go[28] * *cnV[28]; - RHS9 -= go[29] * *cnV[29]; - m_A20 += gt[30]; - m_A20 += gt[31]; - m_A20 += gt[32]; - m_A21 += go[30]; - double RHS10 = Idr[30]; - RHS10 += Idr[31]; - RHS10 += Idr[32]; - RHS10 -= go[31] * *cnV[31]; - RHS10 -= go[32] * *cnV[32]; - m_A22 += gt[33]; - m_A22 += gt[34]; - m_A22 += gt[35]; - m_A23 += go[33]; - double RHS11 = Idr[33]; - RHS11 += Idr[34]; - RHS11 += Idr[35]; - RHS11 -= go[34] * *cnV[34]; - RHS11 -= go[35] * *cnV[35]; - m_A25 += gt[36]; - m_A25 += gt[37]; - m_A25 += gt[38]; - m_A26 += go[36]; - m_A24 += go[37]; - double RHS12 = Idr[36]; - RHS12 += Idr[37]; - RHS12 += Idr[38]; - RHS12 -= go[38] * *cnV[38]; - m_A30 += gt[39]; - m_A30 += gt[40]; - m_A30 += gt[41]; - m_A30 += gt[42]; - m_A30 += gt[43]; - m_A30 += gt[44]; - m_A30 += gt[45]; - m_A29 += go[39]; - m_A28 += go[40]; - m_A27 += go[41]; - m_A31 += go[42]; - m_A31 += go[43]; - double RHS13 = Idr[39]; - RHS13 += Idr[40]; - RHS13 += Idr[41]; - RHS13 += Idr[42]; - RHS13 += Idr[43]; - RHS13 += Idr[44]; - RHS13 += Idr[45]; - RHS13 -= go[44] * *cnV[44]; - RHS13 -= go[45] * *cnV[45]; - m_A42 += gt[46]; - m_A42 += gt[47]; - m_A42 += gt[48]; - m_A42 += gt[49]; - m_A42 += gt[50]; - m_A42 += gt[51]; - m_A42 += gt[52]; - m_A42 += gt[53]; - m_A42 += gt[54]; - m_A42 += gt[55]; - m_A42 += gt[56]; - m_A42 += gt[57]; - m_A42 += gt[58]; - m_A41 += go[46]; - m_A41 += go[47]; - m_A39 += go[48]; - m_A38 += go[49]; - m_A37 += go[50]; - m_A36 += go[51]; - m_A35 += go[52]; - m_A34 += go[53]; - m_A33 += go[54]; - m_A32 += go[55]; - m_A40 += go[56]; - double RHS14 = Idr[46]; - RHS14 += Idr[47]; - RHS14 += Idr[48]; - RHS14 += Idr[49]; - RHS14 += Idr[50]; - RHS14 += Idr[51]; - RHS14 += Idr[52]; - RHS14 += Idr[53]; - RHS14 += Idr[54]; - RHS14 += Idr[55]; - RHS14 += Idr[56]; - RHS14 += Idr[57]; - RHS14 += Idr[58]; - RHS14 -= go[57] * *cnV[57]; - RHS14 -= go[58] * *cnV[58]; const double f0 = 1.0 / m_A0; - const double f0_12 = -f0 * m_A24; - m_A25 += m_A1 * f0_12; - RHS12 += f0_12 * RHS0; + const double f0_7 = -f0 * m_A16; + m_A21 += m_A1 * f0_7; + RHS7 += f0_7 * RHS0; const double f1 = 1.0 / m_A2; - const double f1_14 = -f1 * m_A32; - m_A42 += m_A3 * f1_14; - RHS14 += f1_14 * RHS1; + const double f1_7 = -f1 * m_A17; + m_A21 += m_A3 * f1_7; + RHS7 += f1_7 * RHS1; const double f2 = 1.0 / m_A4; - const double f2_14 = -f2 * m_A33; - m_A42 += m_A5 * f2_14; - RHS14 += f2_14 * RHS2; + const double f2_6 = -f2 * m_A12; + m_A14 += m_A5 * f2_6; + RHS6 += f2_6 * RHS2; const double f3 = 1.0 / m_A6; - const double f3_14 = -f3 * m_A34; - m_A42 += m_A7 * f3_14; - RHS14 += f3_14 * RHS3; + const double f3_6 = -f3 * m_A13; + m_A14 += m_A7 * f3_6; + RHS6 += f3_6 * RHS3; const double f4 = 1.0 / m_A8; - const double f4_14 = -f4 * m_A35; - m_A42 += m_A9 * f4_14; - RHS14 += f4_14 * RHS4; + const double f4_7 = -f4 * m_A18; + m_A21 += m_A9 * f4_7; + RHS7 += f4_7 * RHS4; const double f5 = 1.0 / m_A10; - const double f5_14 = -f5 * m_A36; - m_A42 += m_A11 * f5_14; - RHS14 += f5_14 * RHS5; - const double f6 = 1.0 / m_A12; - const double f6_14 = -f6 * m_A37; - m_A42 += m_A13 * f6_14; - RHS14 += f6_14 * RHS6; - const double f7 = 1.0 / m_A14; - const double f7_14 = -f7 * m_A38; - m_A42 += m_A15 * f7_14; - RHS14 += f7_14 * RHS7; - const double f8 = 1.0 / m_A16; - const double f8_14 = -f8 * m_A39; - m_A42 += m_A17 * f8_14; - RHS14 += f8_14 * RHS8; - const double f9 = 1.0 / m_A18; - const double f9_13 = -f9 * m_A27; - m_A30 += m_A19 * f9_13; - RHS13 += f9_13 * RHS9; - const double f10 = 1.0 / m_A20; - const double f10_13 = -f10 * m_A28; - m_A30 += m_A21 * f10_13; - RHS13 += f10_13 * RHS10; - const double f11 = 1.0 / m_A22; - const double f11_13 = -f11 * m_A29; - m_A30 += m_A23 * f11_13; - RHS13 += f11_13 * RHS11; - const double f12 = 1.0 / m_A25; - const double f12_14 = -f12 * m_A40; - m_A42 += m_A26 * f12_14; - RHS14 += f12_14 * RHS12; - const double f13 = 1.0 / m_A30; - const double f13_14 = -f13 * m_A41; - m_A42 += m_A31 * f13_14; - RHS14 += f13_14 * RHS13; - V[14] = RHS14 / m_A42; - double tmp13 = 0.0; - tmp13 += m_A31 * V[14]; - V[13] = (RHS13 - tmp13) / m_A30; - double tmp12 = 0.0; - tmp12 += m_A26 * V[14]; - V[12] = (RHS12 - tmp12) / m_A25; - double tmp11 = 0.0; - tmp11 += m_A23 * V[13]; - V[11] = (RHS11 - tmp11) / m_A22; - double tmp10 = 0.0; - tmp10 += m_A21 * V[13]; - V[10] = (RHS10 - tmp10) / m_A20; - double tmp9 = 0.0; - tmp9 += m_A19 * V[13]; - V[9] = (RHS9 - tmp9) / m_A18; - double tmp8 = 0.0; - tmp8 += m_A17 * V[14]; - V[8] = (RHS8 - tmp8) / m_A16; - double tmp7 = 0.0; - tmp7 += m_A15 * V[14]; - V[7] = (RHS7 - tmp7) / m_A14; + const double f5_7 = -f5 * m_A19; + m_A21 += m_A11 * f5_7; + RHS7 += f5_7 * RHS5; + const double f6 = 1.0 / m_A14; + const double f6_7 = -f6 * m_A20; + m_A21 += m_A15 * f6_7; + RHS7 += f6_7 * RHS6; + V[7] = RHS7 / m_A21; double tmp6 = 0.0; - tmp6 += m_A13 * V[14]; - V[6] = (RHS6 - tmp6) / m_A12; + tmp6 += m_A15 * V[7]; + V[6] = (RHS6 - tmp6) / m_A14; double tmp5 = 0.0; - tmp5 += m_A11 * V[14]; + tmp5 += m_A11 * V[7]; V[5] = (RHS5 - tmp5) / m_A10; double tmp4 = 0.0; - tmp4 += m_A9 * V[14]; + tmp4 += m_A9 * V[7]; V[4] = (RHS4 - tmp4) / m_A8; double tmp3 = 0.0; - tmp3 += m_A7 * V[14]; + tmp3 += m_A7 * V[6]; V[3] = (RHS3 - tmp3) / m_A6; double tmp2 = 0.0; - tmp2 += m_A5 * V[14]; + tmp2 += m_A5 * V[6]; V[2] = (RHS2 - tmp2) / m_A4; double tmp1 = 0.0; - tmp1 += m_A3 * V[14]; + tmp1 += m_A3 * V[7]; V[1] = (RHS1 - tmp1) / m_A2; double tmp0 = 0.0; - tmp0 += m_A1 * V[12]; + tmp0 += m_A1 * V[7]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// gtrak10,elim,zektor +static void nl_gcr_7_double_double_d190a0e3b8e1f4a7(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A3 += go[2]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 -= go[3] * *cnV[3]; + m_A6 += gt[4]; + m_A6 += gt[5]; + m_A6 += gt[6]; + m_A5 += go[4]; + m_A4 += go[5]; + double RHS2 = Idr[4]; + RHS2 += Idr[5]; + RHS2 += Idr[6]; + RHS2 -= go[6] * *cnV[6]; + const double f0 = 1.0 / m_A0; + const double f0_2 = -f0 * m_A4; + m_A6 += m_A1 * f0_2; + RHS2 += f0_2 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + RHS2 += f1_2 * RHS1; + V[2] = RHS2 / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[2]; V[0] = (RHS0 - tmp0) / m_A0; } @@ -44601,6 +43219,107 @@ static void nl_gcr_50_double_double_c6f25bb06e161d1c(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } +// rebound,astrob +static void nl_gcr_13_double_double_a41a44bd5c424f88(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 -= go[4] * *cnV[4]; + RHS1 -= go[5] * *cnV[5]; + m_A4 += gt[6]; + m_A4 += gt[7]; + m_A4 += gt[8]; + m_A5 += go[6]; + double RHS2 = Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 -= go[7] * *cnV[7]; + RHS2 -= go[8] * *cnV[8]; + m_A6 += gt[9]; + m_A6 += gt[10]; + m_A6 += gt[11]; + m_A7 += go[9]; + double RHS3 = Idr[9]; + RHS3 += Idr[10]; + RHS3 += Idr[11]; + RHS3 -= go[10] * *cnV[10]; + RHS3 -= go[11] * *cnV[11]; + m_A12 += gt[12]; + m_A12 += gt[13]; + m_A12 += gt[14]; + m_A12 += gt[15]; + m_A12 += gt[16]; + m_A11 += go[12]; + m_A10 += go[13]; + m_A9 += go[14]; + m_A8 += go[15]; + double RHS4 = Idr[12]; + RHS4 += Idr[13]; + RHS4 += Idr[14]; + RHS4 += Idr[15]; + RHS4 += Idr[16]; + RHS4 -= go[16] * *cnV[16]; + const double f0 = 1.0 / m_A0; + const double f0_4 = -f0 * m_A8; + m_A12 += m_A1 * f0_4; + RHS4 += f0_4 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_4 = -f1 * m_A9; + m_A12 += m_A3 * f1_4; + RHS4 += f1_4 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_4 = -f2 * m_A10; + m_A12 += m_A5 * f2_4; + RHS4 += f2_4 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_4 = -f3 * m_A11; + m_A12 += m_A7 * f3_4; + RHS4 += f3_4 * RHS3; + V[4] = RHS4 / m_A12; + double tmp3 = 0.0; + tmp3 += m_A7 * V[4]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[4]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[4]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[4]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // rebound static void nl_gcr_28_double_double_8bec817b324dcc3(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -45050,102 +43769,6 @@ static void nl_gcr_11_double_double_aa07266ef5d420d1(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// ripoff,sundance,warrior -static void nl_gcr_12_double_double_295cf2e2f3d489bf(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A2 += gt[5]; - m_A4 += go[2]; - m_A3 += go[3]; - m_A3 += go[4]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 += Idr[4]; - RHS1 += Idr[5]; - RHS1 -= go[5] * *cnV[5]; - m_A6 += gt[6]; - m_A6 += gt[7]; - m_A6 += gt[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A7 += go[6]; - m_A7 += go[7]; - m_A5 += go[8]; - m_A5 += go[9]; - double RHS2 = Idr[6]; - RHS2 += Idr[7]; - RHS2 += Idr[8]; - RHS2 += Idr[9]; - RHS2 += Idr[10]; - RHS2 -= go[10] * *cnV[10]; - m_A11 += gt[11]; - m_A11 += gt[12]; - m_A11 += gt[13]; - m_A11 += gt[14]; - m_A11 += gt[15]; - m_A10 += go[11]; - m_A10 += go[12]; - m_A9 += go[13]; - m_A8 += go[14]; - double RHS3 = Idr[11]; - RHS3 += Idr[12]; - RHS3 += Idr[13]; - RHS3 += Idr[14]; - RHS3 += Idr[15]; - RHS3 -= go[15] * *cnV[15]; - const double f0 = 1.0 / m_A0; - const double f0_3 = -f0 * m_A8; - m_A11 += m_A1 * f0_3; - RHS3 += f0_3 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_2 = -f1 * m_A5; - m_A6 += m_A3 * f1_2; - m_A7 += m_A4 * f1_2; - RHS2 += f1_2 * RHS1; - const double f1_3 = -f1 * m_A9; - m_A10 += m_A3 * f1_3; - m_A11 += m_A4 * f1_3; - RHS3 += f1_3 * RHS1; - const double f2 = 1.0 / m_A6; - const double f2_3 = -f2 * m_A10; - m_A11 += m_A7 * f2_3; - RHS3 += f2_3 * RHS2; - V[3] = RHS3 / m_A11; - double tmp2 = 0.0; - tmp2 += m_A7 * V[3]; - V[2] = (RHS2 - tmp2) / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[2]; - tmp1 += m_A4 * V[3]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[3]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // ripoff static void nl_gcr_16_double_double_698d5dd47fb16d5(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -59446,6 +58069,63 @@ static void nl_gcr_37_double_double_e4f2ffbf201a3d0c(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } +// speedfrk,cheekyms,rebound,astrob,fireone +static void nl_gcr_7_double_double_7c86a9bc1c6aef4c(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 -= go[4] * *cnV[4]; + m_A6 += gt[5]; + m_A6 += gt[6]; + m_A6 += gt[7]; + m_A6 += gt[8]; + m_A5 += go[5]; + m_A4 += go[6]; + double RHS2 = Idr[5]; + RHS2 += Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 -= go[7] * *cnV[7]; + RHS2 -= go[8] * *cnV[8]; + const double f0 = 1.0 / m_A0; + const double f0_2 = -f0 * m_A4; + m_A6 += m_A1 * f0_2; + RHS2 += f0_2 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + RHS2 += f1_2 * RHS1; + V[2] = RHS2 / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[2]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // speedfrk static void nl_gcr_7_double_double_e07b5b086812756c(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -59582,6 +58262,2340 @@ static void nl_gcr_10_double_double_ac1e401ddf971e15(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } +// sspeedr,280zzzap +static void nl_gcr_113_double_double_ab9144d965a37e4(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + double m_A54(0.0); + double m_A55(0.0); + double m_A56(0.0); + double m_A57(0.0); + double m_A58(0.0); + double m_A59(0.0); + double m_A60(0.0); + double m_A61(0.0); + double m_A62(0.0); + double m_A63(0.0); + double m_A64(0.0); + double m_A65(0.0); + double m_A66(0.0); + double m_A67(0.0); + double m_A68(0.0); + double m_A69(0.0); + double m_A70(0.0); + double m_A71(0.0); + double m_A72(0.0); + double m_A73(0.0); + double m_A74(0.0); + double m_A75(0.0); + double m_A76(0.0); + double m_A77(0.0); + double m_A78(0.0); + double m_A79(0.0); + double m_A80(0.0); + double m_A81(0.0); + double m_A82(0.0); + double m_A83(0.0); + double m_A84(0.0); + double m_A85(0.0); + double m_A86(0.0); + double m_A87(0.0); + double m_A88(0.0); + double m_A89(0.0); + double m_A90(0.0); + double m_A91(0.0); + double m_A92(0.0); + double m_A93(0.0); + double m_A94(0.0); + double m_A95(0.0); + double m_A96(0.0); + double m_A97(0.0); + double m_A98(0.0); + double m_A99(0.0); + double m_A100(0.0); + double m_A101(0.0); + double m_A102(0.0); + double m_A103(0.0); + double m_A104(0.0); + double m_A105(0.0); + double m_A106(0.0); + double m_A107(0.0); + double m_A108(0.0); + double m_A109(0.0); + double m_A110(0.0); + double m_A111(0.0); + double m_A112(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A5 += go[2]; + m_A4 += go[3]; + m_A3 += go[4]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 -= go[5] * *cnV[5]; + m_A6 += gt[6]; + m_A6 += gt[7]; + m_A7 += go[6]; + double RHS2 = Idr[6]; + RHS2 += Idr[7]; + RHS2 -= go[7] * *cnV[7]; + m_A8 += gt[8]; + m_A8 += gt[9]; + m_A9 += go[8]; + double RHS3 = Idr[8]; + RHS3 += Idr[9]; + RHS3 -= go[9] * *cnV[9]; + m_A10 += gt[10]; + m_A10 += gt[11]; + m_A10 += gt[12]; + m_A11 += go[10]; + m_A12 += go[11]; + double RHS4 = Idr[10]; + RHS4 += Idr[11]; + RHS4 += Idr[12]; + RHS4 -= go[12] * *cnV[12]; + m_A13 += gt[13]; + m_A13 += gt[14]; + m_A14 += go[13]; + double RHS5 = Idr[13]; + RHS5 += Idr[14]; + RHS5 -= go[14] * *cnV[14]; + m_A15 += gt[15]; + m_A15 += gt[16]; + m_A15 += gt[17]; + m_A15 += gt[18]; + m_A15 += gt[19]; + m_A15 += gt[20]; + m_A15 += gt[21]; + m_A18 += go[15]; + m_A19 += go[16]; + m_A17 += go[17]; + m_A16 += go[18]; + double RHS6 = Idr[15]; + RHS6 += Idr[16]; + RHS6 += Idr[17]; + RHS6 += Idr[18]; + RHS6 += Idr[19]; + RHS6 += Idr[20]; + RHS6 += Idr[21]; + RHS6 -= go[19] * *cnV[19]; + RHS6 -= go[20] * *cnV[20]; + RHS6 -= go[21] * *cnV[21]; + m_A20 += gt[22]; + m_A20 += gt[23]; + m_A20 += gt[24]; + m_A20 += gt[25]; + m_A20 += gt[26]; + m_A20 += gt[27]; + m_A20 += gt[28]; + m_A23 += go[22]; + m_A24 += go[23]; + m_A22 += go[24]; + m_A21 += go[25]; + double RHS7 = Idr[22]; + RHS7 += Idr[23]; + RHS7 += Idr[24]; + RHS7 += Idr[25]; + RHS7 += Idr[26]; + RHS7 += Idr[27]; + RHS7 += Idr[28]; + RHS7 -= go[26] * *cnV[26]; + RHS7 -= go[27] * *cnV[27]; + RHS7 -= go[28] * *cnV[28]; + m_A25 += gt[29]; + m_A25 += gt[30]; + m_A25 += gt[31]; + m_A26 += go[29]; + m_A27 += go[30]; + double RHS8 = Idr[29]; + RHS8 += Idr[30]; + RHS8 += Idr[31]; + RHS8 -= go[31] * *cnV[31]; + m_A28 += gt[32]; + m_A28 += gt[33]; + m_A29 += go[32]; + double RHS9 = Idr[32]; + RHS9 += Idr[33]; + RHS9 -= go[33] * *cnV[33]; + m_A30 += gt[34]; + m_A30 += gt[35]; + m_A30 += gt[36]; + m_A30 += gt[37]; + m_A31 += go[34]; + double RHS10 = Idr[34]; + RHS10 += Idr[35]; + RHS10 += Idr[36]; + RHS10 += Idr[37]; + RHS10 -= go[35] * *cnV[35]; + RHS10 -= go[36] * *cnV[36]; + RHS10 -= go[37] * *cnV[37]; + m_A32 += gt[38]; + m_A32 += gt[39]; + m_A33 += go[38]; + double RHS11 = Idr[38]; + RHS11 += Idr[39]; + RHS11 -= go[39] * *cnV[39]; + m_A36 += gt[40]; + m_A36 += gt[41]; + m_A36 += gt[42]; + m_A36 += gt[43]; + m_A35 += go[40]; + m_A34 += go[41]; + double RHS12 = Idr[40]; + RHS12 += Idr[41]; + RHS12 += Idr[42]; + RHS12 += Idr[43]; + RHS12 -= go[42] * *cnV[42]; + RHS12 -= go[43] * *cnV[43]; + m_A42 += gt[44]; + m_A42 += gt[45]; + m_A42 += gt[46]; + m_A42 += gt[47]; + m_A40 += go[44]; + m_A39 += go[45]; + double RHS13 = Idr[44]; + RHS13 += Idr[45]; + RHS13 += Idr[46]; + RHS13 += Idr[47]; + RHS13 -= go[46] * *cnV[46]; + RHS13 -= go[47] * *cnV[47]; + m_A51 += gt[48]; + m_A51 += gt[49]; + m_A51 += gt[50]; + m_A51 += gt[51]; + m_A53 += go[48]; + m_A48 += go[49]; + m_A47 += go[50]; + double RHS14 = Idr[48]; + RHS14 += Idr[49]; + RHS14 += Idr[50]; + RHS14 += Idr[51]; + RHS14 -= go[51] * *cnV[51]; + m_A57 += gt[52]; + m_A57 += gt[53]; + m_A57 += gt[54]; + m_A56 += go[52]; + m_A58 += go[53]; + double RHS15 = Idr[52]; + RHS15 += Idr[53]; + RHS15 += Idr[54]; + RHS15 -= go[54] * *cnV[54]; + m_A60 += gt[55]; + m_A60 += gt[56]; + m_A60 += gt[57]; + m_A60 += gt[58]; + m_A59 += go[55]; + m_A61 += go[56]; + double RHS16 = Idr[55]; + RHS16 += Idr[56]; + RHS16 += Idr[57]; + RHS16 += Idr[58]; + RHS16 -= go[57] * *cnV[57]; + RHS16 -= go[58] * *cnV[58]; + m_A67 += gt[59]; + m_A67 += gt[60]; + m_A67 += gt[61]; + m_A67 += gt[62]; + m_A67 += gt[63]; + m_A67 += gt[64]; + m_A70 += go[59]; + m_A64 += go[60]; + m_A63 += go[61]; + m_A62 += go[62]; + m_A69 += go[63]; + double RHS17 = Idr[59]; + RHS17 += Idr[60]; + RHS17 += Idr[61]; + RHS17 += Idr[62]; + RHS17 += Idr[63]; + RHS17 += Idr[64]; + RHS17 -= go[64] * *cnV[64]; + m_A74 += gt[65]; + m_A74 += gt[66]; + m_A74 += gt[67]; + m_A74 += gt[68]; + m_A73 += go[65]; + m_A72 += go[66]; + m_A75 += go[67]; + double RHS18 = Idr[65]; + RHS18 += Idr[66]; + RHS18 += Idr[67]; + RHS18 += Idr[68]; + RHS18 -= go[68] * *cnV[68]; + m_A80 += gt[69]; + m_A80 += gt[70]; + m_A80 += gt[71]; + m_A80 += gt[72]; + m_A80 += gt[73]; + m_A77 += go[69]; + m_A78 += go[70]; + m_A76 += go[71]; + double RHS19 = Idr[69]; + RHS19 += Idr[70]; + RHS19 += Idr[71]; + RHS19 += Idr[72]; + RHS19 += Idr[73]; + RHS19 -= go[72] * *cnV[72]; + RHS19 -= go[73] * *cnV[73]; + m_A89 += gt[74]; + m_A89 += gt[75]; + m_A89 += gt[76]; + m_A89 += gt[77]; + m_A84 += go[74]; + m_A85 += go[75]; + m_A87 += go[76]; + m_A86 += go[77]; + double RHS20 = Idr[74]; + RHS20 += Idr[75]; + RHS20 += Idr[76]; + RHS20 += Idr[77]; + m_A100 += gt[78]; + m_A100 += gt[79]; + m_A100 += gt[80]; + m_A100 += gt[81]; + m_A100 += gt[82]; + m_A100 += gt[83]; + m_A100 += gt[84]; + m_A96 += go[78]; + m_A93 += go[79]; + m_A101 += go[80]; + m_A92 += go[81]; + m_A97 += go[82]; + double RHS21 = Idr[78]; + RHS21 += Idr[79]; + RHS21 += Idr[80]; + RHS21 += Idr[81]; + RHS21 += Idr[82]; + RHS21 += Idr[83]; + RHS21 += Idr[84]; + RHS21 -= go[83] * *cnV[83]; + RHS21 -= go[84] * *cnV[84]; + m_A112 += gt[85]; + m_A112 += gt[86]; + m_A112 += gt[87]; + m_A112 += gt[88]; + m_A112 += gt[89]; + m_A112 += gt[90]; + m_A108 += go[85]; + m_A111 += go[86]; + m_A103 += go[87]; + m_A104 += go[88]; + m_A102 += go[89]; + double RHS22 = Idr[85]; + RHS22 += Idr[86]; + RHS22 += Idr[87]; + RHS22 += Idr[88]; + RHS22 += Idr[89]; + RHS22 += Idr[90]; + RHS22 -= go[90] * *cnV[90]; + const double f0 = 1.0 / m_A0; + const double f0_12 = -f0 * m_A34; + m_A36 += m_A1 * f0_12; + RHS12 += f0_12 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_12 = -f1 * m_A35; + m_A36 += m_A3 * f1_12; + m_A37 += m_A4 * f1_12; + m_A38 += m_A5 * f1_12; + RHS12 += f1_12 * RHS1; + const double f1_13 = -f1 * m_A39; + m_A41 += m_A3 * f1_13; + m_A42 += m_A4 * f1_13; + m_A43 += m_A5 * f1_13; + RHS13 += f1_13 * RHS1; + const double f1_14 = -f1 * m_A47; + m_A49 += m_A3 * f1_14; + m_A50 += m_A4 * f1_14; + m_A51 += m_A5 * f1_14; + RHS14 += f1_14 * RHS1; + const double f2 = 1.0 / m_A6; + const double f2_15 = -f2 * m_A56; + m_A57 += m_A7 * f2_15; + RHS15 += f2_15 * RHS2; + const double f3 = 1.0 / m_A8; + const double f3_20 = -f3 * m_A84; + m_A89 += m_A9 * f3_20; + RHS20 += f3_20 * RHS3; + const double f4 = 1.0 / m_A10; + const double f4_17 = -f4 * m_A62; + m_A67 += m_A11 * f4_17; + m_A69 += m_A12 * f4_17; + RHS17 += f4_17 * RHS4; + const double f4_20 = -f4 * m_A85; + m_A87 += m_A11 * f4_20; + m_A89 += m_A12 * f4_20; + RHS20 += f4_20 * RHS4; + const double f5 = 1.0 / m_A13; + const double f5_16 = -f5 * m_A59; + m_A60 += m_A14 * f5_16; + RHS16 += f5_16 * RHS5; + const double f6 = 1.0 / m_A15; + const double f6_13 = -f6 * m_A40; + m_A42 += m_A16 * f6_13; + m_A44 += m_A17 * f6_13; + m_A45 += m_A18 * f6_13; + m_A46 += m_A19 * f6_13; + RHS13 += f6_13 * RHS6; + const double f6_17 = -f6 * m_A63; + m_A65 += m_A16 * f6_17; + m_A67 += m_A17 * f6_17; + m_A70 += m_A18 * f6_17; + m_A71 += m_A19 * f6_17; + RHS17 += f6_17 * RHS6; + const double f6_21 = -f6 * m_A92; + m_A94 += m_A16 * f6_21; + m_A97 += m_A17 * f6_21; + m_A100 += m_A18 * f6_21; + m_A101 += m_A19 * f6_21; + RHS21 += f6_21 * RHS6; + const double f6_22 = -f6 * m_A102; + m_A105 += m_A16 * f6_22; + m_A107 += m_A17 * f6_22; + m_A111 += m_A18 * f6_22; + m_A112 += m_A19 * f6_22; + RHS22 += f6_22 * RHS6; + const double f7 = 1.0 / m_A20; + const double f7_14 = -f7 * m_A48; + m_A51 += m_A21 * f7_14; + m_A52 += m_A22 * f7_14; + m_A54 += m_A23 * f7_14; + m_A55 += m_A24 * f7_14; + RHS14 += f7_14 * RHS7; + const double f7_17 = -f7 * m_A64; + m_A66 += m_A21 * f7_17; + m_A67 += m_A22 * f7_17; + m_A70 += m_A23 * f7_17; + m_A71 += m_A24 * f7_17; + RHS17 += f7_17 * RHS7; + const double f7_21 = -f7 * m_A93; + m_A95 += m_A21 * f7_21; + m_A97 += m_A22 * f7_21; + m_A100 += m_A23 * f7_21; + m_A101 += m_A24 * f7_21; + RHS21 += f7_21 * RHS7; + const double f7_22 = -f7 * m_A103; + m_A106 += m_A21 * f7_22; + m_A107 += m_A22 * f7_22; + m_A111 += m_A23 * f7_22; + m_A112 += m_A24 * f7_22; + RHS22 += f7_22 * RHS7; + const double f8 = 1.0 / m_A25; + const double f8_18 = -f8 * m_A72; + m_A74 += m_A26 * f8_18; + m_A75 += m_A27 * f8_18; + RHS18 += f8_18 * RHS8; + const double f8_22 = -f8 * m_A104; + m_A108 += m_A26 * f8_22; + m_A112 += m_A27 * f8_22; + RHS22 += f8_22 * RHS8; + const double f9 = 1.0 / m_A28; + const double f9_18 = -f9 * m_A73; + m_A74 += m_A29 * f9_18; + RHS18 += f9_18 * RHS9; + const double f10 = 1.0 / m_A30; + const double f10_19 = -f10 * m_A76; + m_A80 += m_A31 * f10_19; + RHS19 += f10_19 * RHS10; + const double f11 = 1.0 / m_A32; + const double f11_19 = -f11 * m_A77; + m_A80 += m_A33 * f11_19; + RHS19 += f11_19 * RHS11; + const double f12 = 1.0 / m_A36; + const double f12_13 = -f12 * m_A41; + m_A42 += m_A37 * f12_13; + m_A43 += m_A38 * f12_13; + RHS13 += f12_13 * RHS12; + const double f12_14 = -f12 * m_A49; + m_A50 += m_A37 * f12_14; + m_A51 += m_A38 * f12_14; + RHS14 += f12_14 * RHS12; + const double f13 = 1.0 / m_A42; + const double f13_14 = -f13 * m_A50; + m_A51 += m_A43 * f13_14; + m_A52 += m_A44 * f13_14; + m_A54 += m_A45 * f13_14; + m_A55 += m_A46 * f13_14; + RHS14 += f13_14 * RHS13; + const double f13_17 = -f13 * m_A65; + m_A66 += m_A43 * f13_17; + m_A67 += m_A44 * f13_17; + m_A70 += m_A45 * f13_17; + m_A71 += m_A46 * f13_17; + RHS17 += f13_17 * RHS13; + const double f13_21 = -f13 * m_A94; + m_A95 += m_A43 * f13_21; + m_A97 += m_A44 * f13_21; + m_A100 += m_A45 * f13_21; + m_A101 += m_A46 * f13_21; + RHS21 += f13_21 * RHS13; + const double f13_22 = -f13 * m_A105; + m_A106 += m_A43 * f13_22; + m_A107 += m_A44 * f13_22; + m_A111 += m_A45 * f13_22; + m_A112 += m_A46 * f13_22; + RHS22 += f13_22 * RHS13; + const double f14 = 1.0 / m_A51; + const double f14_17 = -f14 * m_A66; + m_A67 += m_A52 * f14_17; + m_A68 += m_A53 * f14_17; + m_A70 += m_A54 * f14_17; + m_A71 += m_A55 * f14_17; + RHS17 += f14_17 * RHS14; + const double f14_19 = -f14 * m_A78; + m_A79 += m_A52 * f14_19; + m_A80 += m_A53 * f14_19; + m_A82 += m_A54 * f14_19; + m_A83 += m_A55 * f14_19; + RHS19 += f14_19 * RHS14; + const double f14_21 = -f14 * m_A95; + m_A97 += m_A52 * f14_21; + m_A98 += m_A53 * f14_21; + m_A100 += m_A54 * f14_21; + m_A101 += m_A55 * f14_21; + RHS21 += f14_21 * RHS14; + const double f14_22 = -f14 * m_A106; + m_A107 += m_A52 * f14_22; + m_A109 += m_A53 * f14_22; + m_A111 += m_A54 * f14_22; + m_A112 += m_A55 * f14_22; + RHS22 += f14_22 * RHS14; + const double f15 = 1.0 / m_A57; + const double f15_20 = -f15 * m_A86; + m_A89 += m_A58 * f15_20; + RHS20 += f15_20 * RHS15; + const double f16 = 1.0 / m_A60; + const double f16_21 = -f16 * m_A96; + m_A100 += m_A61 * f16_21; + RHS21 += f16_21 * RHS16; + const double f17 = 1.0 / m_A67; + const double f17_19 = -f17 * m_A79; + m_A80 += m_A68 * f17_19; + m_A81 += m_A69 * f17_19; + m_A82 += m_A70 * f17_19; + m_A83 += m_A71 * f17_19; + RHS19 += f17_19 * RHS17; + const double f17_20 = -f17 * m_A87; + m_A88 += m_A68 * f17_20; + m_A89 += m_A69 * f17_20; + m_A90 += m_A70 * f17_20; + m_A91 += m_A71 * f17_20; + RHS20 += f17_20 * RHS17; + const double f17_21 = -f17 * m_A97; + m_A98 += m_A68 * f17_21; + m_A99 += m_A69 * f17_21; + m_A100 += m_A70 * f17_21; + m_A101 += m_A71 * f17_21; + RHS21 += f17_21 * RHS17; + const double f17_22 = -f17 * m_A107; + m_A109 += m_A68 * f17_22; + m_A110 += m_A69 * f17_22; + m_A111 += m_A70 * f17_22; + m_A112 += m_A71 * f17_22; + RHS22 += f17_22 * RHS17; + const double f18 = 1.0 / m_A74; + const double f18_22 = -f18 * m_A108; + m_A112 += m_A75 * f18_22; + RHS22 += f18_22 * RHS18; + const double f19 = 1.0 / m_A80; + const double f19_20 = -f19 * m_A88; + m_A89 += m_A81 * f19_20; + m_A90 += m_A82 * f19_20; + m_A91 += m_A83 * f19_20; + RHS20 += f19_20 * RHS19; + const double f19_21 = -f19 * m_A98; + m_A99 += m_A81 * f19_21; + m_A100 += m_A82 * f19_21; + m_A101 += m_A83 * f19_21; + RHS21 += f19_21 * RHS19; + const double f19_22 = -f19 * m_A109; + m_A110 += m_A81 * f19_22; + m_A111 += m_A82 * f19_22; + m_A112 += m_A83 * f19_22; + RHS22 += f19_22 * RHS19; + const double f20 = 1.0 / m_A89; + const double f20_21 = -f20 * m_A99; + m_A100 += m_A90 * f20_21; + m_A101 += m_A91 * f20_21; + RHS21 += f20_21 * RHS20; + const double f20_22 = -f20 * m_A110; + m_A111 += m_A90 * f20_22; + m_A112 += m_A91 * f20_22; + RHS22 += f20_22 * RHS20; + const double f21 = 1.0 / m_A100; + const double f21_22 = -f21 * m_A111; + m_A112 += m_A101 * f21_22; + RHS22 += f21_22 * RHS21; + V[22] = RHS22 / m_A112; + double tmp21 = 0.0; + tmp21 += m_A101 * V[22]; + V[21] = (RHS21 - tmp21) / m_A100; + double tmp20 = 0.0; + tmp20 += m_A90 * V[21]; + tmp20 += m_A91 * V[22]; + V[20] = (RHS20 - tmp20) / m_A89; + double tmp19 = 0.0; + tmp19 += m_A81 * V[20]; + tmp19 += m_A82 * V[21]; + tmp19 += m_A83 * V[22]; + V[19] = (RHS19 - tmp19) / m_A80; + double tmp18 = 0.0; + tmp18 += m_A75 * V[22]; + V[18] = (RHS18 - tmp18) / m_A74; + double tmp17 = 0.0; + tmp17 += m_A68 * V[19]; + tmp17 += m_A69 * V[20]; + tmp17 += m_A70 * V[21]; + tmp17 += m_A71 * V[22]; + V[17] = (RHS17 - tmp17) / m_A67; + double tmp16 = 0.0; + tmp16 += m_A61 * V[21]; + V[16] = (RHS16 - tmp16) / m_A60; + double tmp15 = 0.0; + tmp15 += m_A58 * V[20]; + V[15] = (RHS15 - tmp15) / m_A57; + double tmp14 = 0.0; + tmp14 += m_A52 * V[17]; + tmp14 += m_A53 * V[19]; + tmp14 += m_A54 * V[21]; + tmp14 += m_A55 * V[22]; + V[14] = (RHS14 - tmp14) / m_A51; + double tmp13 = 0.0; + tmp13 += m_A43 * V[14]; + tmp13 += m_A44 * V[17]; + tmp13 += m_A45 * V[21]; + tmp13 += m_A46 * V[22]; + V[13] = (RHS13 - tmp13) / m_A42; + double tmp12 = 0.0; + tmp12 += m_A37 * V[13]; + tmp12 += m_A38 * V[14]; + V[12] = (RHS12 - tmp12) / m_A36; + double tmp11 = 0.0; + tmp11 += m_A33 * V[19]; + V[11] = (RHS11 - tmp11) / m_A32; + double tmp10 = 0.0; + tmp10 += m_A31 * V[19]; + V[10] = (RHS10 - tmp10) / m_A30; + double tmp9 = 0.0; + tmp9 += m_A29 * V[18]; + V[9] = (RHS9 - tmp9) / m_A28; + double tmp8 = 0.0; + tmp8 += m_A26 * V[18]; + tmp8 += m_A27 * V[22]; + V[8] = (RHS8 - tmp8) / m_A25; + double tmp7 = 0.0; + tmp7 += m_A21 * V[14]; + tmp7 += m_A22 * V[17]; + tmp7 += m_A23 * V[21]; + tmp7 += m_A24 * V[22]; + V[7] = (RHS7 - tmp7) / m_A20; + double tmp6 = 0.0; + tmp6 += m_A16 * V[13]; + tmp6 += m_A17 * V[17]; + tmp6 += m_A18 * V[21]; + tmp6 += m_A19 * V[22]; + V[6] = (RHS6 - tmp6) / m_A15; + double tmp5 = 0.0; + tmp5 += m_A14 * V[16]; + V[5] = (RHS5 - tmp5) / m_A13; + double tmp4 = 0.0; + tmp4 += m_A11 * V[17]; + tmp4 += m_A12 * V[20]; + V[4] = (RHS4 - tmp4) / m_A10; + double tmp3 = 0.0; + tmp3 += m_A9 * V[20]; + V[3] = (RHS3 - tmp3) / m_A8; + double tmp2 = 0.0; + tmp2 += m_A7 * V[15]; + V[2] = (RHS2 - tmp2) / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[12]; + tmp1 += m_A4 * V[13]; + tmp1 += m_A5 * V[14]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[12]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// sspeedr,280zzzap +static void nl_gcr_122_double_double_42c57d523cac30d0(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + double m_A54(0.0); + double m_A55(0.0); + double m_A56(0.0); + double m_A57(0.0); + double m_A58(0.0); + double m_A59(0.0); + double m_A60(0.0); + double m_A61(0.0); + double m_A62(0.0); + double m_A63(0.0); + double m_A64(0.0); + double m_A65(0.0); + double m_A66(0.0); + double m_A67(0.0); + double m_A68(0.0); + double m_A69(0.0); + double m_A70(0.0); + double m_A71(0.0); + double m_A72(0.0); + double m_A73(0.0); + double m_A74(0.0); + double m_A75(0.0); + double m_A76(0.0); + double m_A77(0.0); + double m_A78(0.0); + double m_A79(0.0); + double m_A80(0.0); + double m_A81(0.0); + double m_A82(0.0); + double m_A83(0.0); + double m_A84(0.0); + double m_A85(0.0); + double m_A86(0.0); + double m_A87(0.0); + double m_A88(0.0); + double m_A89(0.0); + double m_A90(0.0); + double m_A91(0.0); + double m_A92(0.0); + double m_A93(0.0); + double m_A94(0.0); + double m_A95(0.0); + double m_A96(0.0); + double m_A97(0.0); + double m_A98(0.0); + double m_A99(0.0); + double m_A100(0.0); + double m_A101(0.0); + double m_A102(0.0); + double m_A103(0.0); + double m_A104(0.0); + double m_A105(0.0); + double m_A106(0.0); + double m_A107(0.0); + double m_A108(0.0); + double m_A109(0.0); + double m_A110(0.0); + double m_A111(0.0); + double m_A112(0.0); + double m_A113(0.0); + double m_A114(0.0); + double m_A115(0.0); + double m_A116(0.0); + double m_A117(0.0); + double m_A118(0.0); + double m_A119(0.0); + double m_A120(0.0); + double m_A121(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A3 += go[2]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 -= go[3] * *cnV[3]; + m_A4 += gt[4]; + m_A4 += gt[5]; + m_A4 += gt[6]; + m_A5 += go[4]; + double RHS2 = Idr[4]; + RHS2 += Idr[5]; + RHS2 += Idr[6]; + RHS2 -= go[5] * *cnV[5]; + RHS2 -= go[6] * *cnV[6]; + m_A6 += gt[7]; + m_A6 += gt[8]; + m_A6 += gt[9]; + m_A6 += gt[10]; + m_A6 += gt[11]; + m_A6 += gt[12]; + m_A6 += gt[13]; + m_A7 += go[7]; + double RHS3 = Idr[7]; + RHS3 += Idr[8]; + RHS3 += Idr[9]; + RHS3 += Idr[10]; + RHS3 += Idr[11]; + RHS3 += Idr[12]; + RHS3 += Idr[13]; + RHS3 -= go[8] * *cnV[8]; + RHS3 -= go[9] * *cnV[9]; + RHS3 -= go[10] * *cnV[10]; + RHS3 -= go[11] * *cnV[11]; + RHS3 -= go[12] * *cnV[12]; + RHS3 -= go[13] * *cnV[13]; + m_A8 += gt[14]; + m_A8 += gt[15]; + m_A9 += go[14]; + double RHS4 = Idr[14]; + RHS4 += Idr[15]; + RHS4 -= go[15] * *cnV[15]; + m_A10 += gt[16]; + m_A10 += gt[17]; + m_A10 += gt[18]; + m_A10 += gt[19]; + m_A12 += go[16]; + m_A13 += go[17]; + m_A11 += go[18]; + double RHS5 = Idr[16]; + RHS5 += Idr[17]; + RHS5 += Idr[18]; + RHS5 += Idr[19]; + RHS5 -= go[19] * *cnV[19]; + m_A14 += gt[20]; + m_A14 += gt[21]; + m_A14 += gt[22]; + m_A14 += gt[23]; + m_A14 += gt[24]; + m_A14 += gt[25]; + m_A14 += gt[26]; + m_A15 += go[20]; + double RHS6 = Idr[20]; + RHS6 += Idr[21]; + RHS6 += Idr[22]; + RHS6 += Idr[23]; + RHS6 += Idr[24]; + RHS6 += Idr[25]; + RHS6 += Idr[26]; + RHS6 -= go[21] * *cnV[21]; + RHS6 -= go[22] * *cnV[22]; + RHS6 -= go[23] * *cnV[23]; + RHS6 -= go[24] * *cnV[24]; + RHS6 -= go[25] * *cnV[25]; + RHS6 -= go[26] * *cnV[26]; + m_A16 += gt[27]; + m_A16 += gt[28]; + m_A18 += go[27]; + m_A17 += go[28]; + double RHS7 = Idr[27]; + RHS7 += Idr[28]; + m_A19 += gt[29]; + m_A19 += gt[30]; + m_A19 += gt[31]; + m_A20 += go[29]; + double RHS8 = Idr[29]; + RHS8 += Idr[30]; + RHS8 += Idr[31]; + RHS8 -= go[30] * *cnV[30]; + RHS8 -= go[31] * *cnV[31]; + m_A21 += gt[32]; + m_A21 += gt[33]; + m_A22 += go[32]; + double RHS9 = Idr[32]; + RHS9 += Idr[33]; + RHS9 -= go[33] * *cnV[33]; + m_A23 += gt[34]; + m_A23 += gt[35]; + m_A23 += gt[36]; + m_A24 += go[34]; + m_A25 += go[35]; + m_A25 += go[36]; + double RHS10 = Idr[34]; + RHS10 += Idr[35]; + RHS10 += Idr[36]; + m_A26 += gt[37]; + m_A26 += gt[38]; + m_A26 += gt[39]; + m_A26 += gt[40]; + m_A26 += gt[41]; + m_A26 += gt[42]; + m_A26 += gt[43]; + m_A27 += go[37]; + double RHS11 = Idr[37]; + RHS11 += Idr[38]; + RHS11 += Idr[39]; + RHS11 += Idr[40]; + RHS11 += Idr[41]; + RHS11 += Idr[42]; + RHS11 += Idr[43]; + RHS11 -= go[38] * *cnV[38]; + RHS11 -= go[39] * *cnV[39]; + RHS11 -= go[40] * *cnV[40]; + RHS11 -= go[41] * *cnV[41]; + RHS11 -= go[42] * *cnV[42]; + RHS11 -= go[43] * *cnV[43]; + m_A28 += gt[44]; + m_A28 += gt[45]; + m_A28 += gt[46]; + m_A29 += go[44]; + double RHS12 = Idr[44]; + RHS12 += Idr[45]; + RHS12 += Idr[46]; + RHS12 -= go[45] * *cnV[45]; + RHS12 -= go[46] * *cnV[46]; + m_A30 += gt[47]; + m_A30 += gt[48]; + m_A30 += gt[49]; + m_A30 += gt[50]; + m_A32 += go[47]; + m_A31 += go[48]; + m_A33 += go[49]; + double RHS13 = Idr[47]; + RHS13 += Idr[48]; + RHS13 += Idr[49]; + RHS13 += Idr[50]; + RHS13 -= go[50] * *cnV[50]; + m_A35 += gt[51]; + m_A35 += gt[52]; + m_A34 += go[51]; + double RHS14 = Idr[51]; + RHS14 += Idr[52]; + RHS14 -= go[52] * *cnV[52]; + m_A37 += gt[53]; + m_A37 += gt[54]; + m_A37 += gt[55]; + m_A37 += gt[56]; + m_A36 += go[53]; + m_A38 += go[54]; + double RHS15 = Idr[53]; + RHS15 += Idr[54]; + RHS15 += Idr[55]; + RHS15 += Idr[56]; + RHS15 -= go[55] * *cnV[55]; + RHS15 -= go[56] * *cnV[56]; + m_A40 += gt[57]; + m_A40 += gt[58]; + m_A39 += go[57]; + double RHS16 = Idr[57]; + RHS16 += Idr[58]; + RHS16 -= go[58] * *cnV[58]; + m_A43 += gt[59]; + m_A43 += gt[60]; + m_A41 += go[59]; + m_A42 += go[60]; + double RHS17 = Idr[59]; + RHS17 += Idr[60]; + m_A47 += gt[61]; + m_A47 += gt[62]; + m_A47 += gt[63]; + m_A47 += gt[64]; + m_A47 += gt[65]; + m_A46 += go[61]; + m_A49 += go[62]; + m_A50 += go[63]; + double RHS18 = Idr[61]; + RHS18 += Idr[62]; + RHS18 += Idr[63]; + RHS18 += Idr[64]; + RHS18 += Idr[65]; + RHS18 -= go[64] * *cnV[64]; + RHS18 -= go[65] * *cnV[65]; + m_A52 += gt[66]; + m_A52 += gt[67]; + m_A51 += go[66]; + double RHS19 = Idr[66]; + RHS19 += Idr[67]; + RHS19 -= go[67] * *cnV[67]; + m_A55 += gt[68]; + m_A55 += gt[69]; + m_A54 += go[68]; + m_A53 += go[69]; + double RHS20 = Idr[68]; + RHS20 += Idr[69]; + m_A60 += gt[70]; + m_A60 += gt[71]; + m_A60 += gt[72]; + m_A60 += gt[73]; + m_A59 += go[70]; + m_A61 += go[71]; + double RHS21 = Idr[70]; + RHS21 += Idr[71]; + RHS21 += Idr[72]; + RHS21 += Idr[73]; + RHS21 -= go[72] * *cnV[72]; + RHS21 -= go[73] * *cnV[73]; + m_A69 += gt[74]; + m_A69 += gt[75]; + m_A69 += gt[76]; + m_A69 += gt[77]; + m_A69 += gt[78]; + m_A69 += gt[79]; + m_A69 += gt[80]; + m_A69 += gt[81]; + m_A69 += gt[82]; + m_A62 += go[74]; + m_A65 += go[75]; + m_A65 += go[76]; + m_A64 += go[77]; + m_A63 += go[78]; + m_A71 += go[79]; + double RHS22 = Idr[74]; + RHS22 += Idr[75]; + RHS22 += Idr[76]; + RHS22 += Idr[77]; + RHS22 += Idr[78]; + RHS22 += Idr[79]; + RHS22 += Idr[80]; + RHS22 += Idr[81]; + RHS22 += Idr[82]; + RHS22 -= go[80] * *cnV[80]; + RHS22 -= go[81] * *cnV[81]; + RHS22 -= go[82] * *cnV[82]; + m_A75 += gt[83]; + m_A75 += gt[84]; + m_A75 += gt[85]; + m_A75 += gt[86]; + m_A74 += go[83]; + m_A76 += go[84]; + double RHS23 = Idr[83]; + RHS23 += Idr[84]; + RHS23 += Idr[85]; + RHS23 += Idr[86]; + RHS23 -= go[85] * *cnV[85]; + RHS23 -= go[86] * *cnV[86]; + m_A82 += gt[87]; + m_A82 += gt[88]; + m_A82 += gt[89]; + m_A82 += gt[90]; + m_A82 += gt[91]; + m_A82 += gt[92]; + m_A77 += go[87]; + m_A78 += go[88]; + m_A84 += go[89]; + double RHS24 = Idr[87]; + RHS24 += Idr[88]; + RHS24 += Idr[89]; + RHS24 += Idr[90]; + RHS24 += Idr[91]; + RHS24 += Idr[92]; + RHS24 -= go[90] * *cnV[90]; + RHS24 -= go[91] * *cnV[91]; + RHS24 -= go[92] * *cnV[92]; + m_A93 += gt[93]; + m_A93 += gt[94]; + m_A93 += gt[95]; + m_A93 += gt[96]; + m_A93 += gt[97]; + m_A91 += go[93]; + m_A89 += go[94]; + m_A88 += go[95]; + m_A87 += go[96]; + m_A86 += go[97]; + double RHS25 = Idr[93]; + RHS25 += Idr[94]; + RHS25 += Idr[95]; + RHS25 += Idr[96]; + RHS25 += Idr[97]; + m_A104 += gt[98]; + m_A104 += gt[99]; + m_A104 += gt[100]; + m_A104 += gt[101]; + m_A104 += gt[102]; + m_A102 += go[98]; + m_A99 += go[99]; + m_A98 += go[100]; + m_A97 += go[101]; + m_A96 += go[102]; + double RHS26 = Idr[98]; + RHS26 += Idr[99]; + RHS26 += Idr[100]; + RHS26 += Idr[101]; + RHS26 += Idr[102]; + m_A113 += gt[103]; + m_A113 += gt[104]; + m_A113 += gt[105]; + m_A113 += gt[106]; + m_A107 += go[103]; + m_A106 += go[104]; + m_A114 += go[105]; + double RHS27 = Idr[103]; + RHS27 += Idr[104]; + RHS27 += Idr[105]; + RHS27 += Idr[106]; + RHS27 -= go[106] * *cnV[106]; + m_A121 += gt[107]; + m_A121 += gt[108]; + m_A121 += gt[109]; + m_A121 += gt[110]; + m_A121 += gt[111]; + m_A118 += go[107]; + m_A117 += go[108]; + m_A120 += go[109]; + m_A116 += go[110]; + m_A115 += go[111]; + double RHS28 = Idr[107]; + RHS28 += Idr[108]; + RHS28 += Idr[109]; + RHS28 += Idr[110]; + RHS28 += Idr[111]; + const double f0 = 1.0 / m_A0; + const double f0_17 = -f0 * m_A41; + m_A43 += m_A1 * f0_17; + RHS17 += f0_17 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_14 = -f1 * m_A34; + m_A35 += m_A3 * f1_14; + RHS14 += f1_14 * RHS1; + const double f1_25 = -f1 * m_A86; + m_A89 += m_A3 * f1_25; + RHS25 += f1_25 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_15 = -f2 * m_A36; + m_A38 += m_A5 * f2_15; + RHS15 += f2_15 * RHS2; + const double f2_25 = -f2 * m_A87; + m_A93 += m_A5 * f2_25; + RHS25 += f2_25 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_22 = -f3 * m_A62; + m_A66 += m_A7 * f3_22; + RHS22 += f3_22 * RHS3; + const double f4 = 1.0 / m_A8; + const double f4_16 = -f4 * m_A39; + m_A40 += m_A9 * f4_16; + RHS16 += f4_16 * RHS4; + const double f4_28 = -f4 * m_A115; + m_A117 += m_A9 * f4_28; + RHS28 += f4_28 * RHS4; + const double f5 = 1.0 / m_A10; + const double f5_17 = -f5 * m_A42; + m_A43 += m_A11 * f5_17; + m_A44 += m_A12 * f5_17; + m_A45 += m_A13 * f5_17; + RHS17 += f5_17 * RHS5; + const double f5_22 = -f5 * m_A63; + m_A67 += m_A11 * f5_22; + m_A69 += m_A12 * f5_22; + m_A71 += m_A13 * f5_22; + RHS22 += f5_22 * RHS5; + const double f5_25 = -f5 * m_A88; + m_A90 += m_A11 * f5_25; + m_A91 += m_A12 * f5_25; + m_A93 += m_A13 * f5_25; + RHS25 += f5_25 * RHS5; + const double f6 = 1.0 / m_A14; + const double f6_18 = -f6 * m_A46; + m_A48 += m_A15 * f6_18; + RHS18 += f6_18 * RHS6; + const double f7 = 1.0 / m_A16; + const double f7_22 = -f7 * m_A64; + m_A69 += m_A17 * f7_22; + m_A73 += m_A18 * f7_22; + RHS22 += f7_22 * RHS7; + const double f7_27 = -f7 * m_A106; + m_A109 += m_A17 * f7_27; + m_A113 += m_A18 * f7_27; + RHS27 += f7_27 * RHS7; + const double f8 = 1.0 / m_A19; + const double f8_21 = -f8 * m_A59; + m_A61 += m_A20 * f8_21; + RHS21 += f8_21 * RHS8; + const double f8_28 = -f8 * m_A116; + m_A121 += m_A20 * f8_28; + RHS28 += f8_28 * RHS8; + const double f9 = 1.0 / m_A21; + const double f9_19 = -f9 * m_A51; + m_A52 += m_A22 * f9_19; + RHS19 += f9_19 * RHS9; + const double f9_26 = -f9 * m_A96; + m_A99 += m_A22 * f9_26; + RHS26 += f9_26 * RHS9; + const double f10 = 1.0 / m_A23; + const double f10_20 = -f10 * m_A53; + m_A55 += m_A24 * f10_20; + m_A56 += m_A25 * f10_20; + RHS20 += f10_20 * RHS10; + const double f10_22 = -f10 * m_A65; + m_A68 += m_A24 * f10_22; + m_A69 += m_A25 * f10_22; + RHS22 += f10_22 * RHS10; + const double f11 = 1.0 / m_A26; + const double f11_24 = -f11 * m_A77; + m_A81 += m_A27 * f11_24; + RHS24 += f11_24 * RHS11; + const double f12 = 1.0 / m_A28; + const double f12_23 = -f12 * m_A74; + m_A76 += m_A29 * f12_23; + RHS23 += f12_23 * RHS12; + const double f12_26 = -f12 * m_A97; + m_A104 += m_A29 * f12_26; + RHS26 += f12_26 * RHS12; + const double f13 = 1.0 / m_A30; + const double f13_20 = -f13 * m_A54; + m_A55 += m_A31 * f13_20; + m_A57 += m_A32 * f13_20; + m_A58 += m_A33 * f13_20; + RHS20 += f13_20 * RHS13; + const double f13_24 = -f13 * m_A78; + m_A79 += m_A31 * f13_24; + m_A82 += m_A32 * f13_24; + m_A84 += m_A33 * f13_24; + RHS24 += f13_24 * RHS13; + const double f13_26 = -f13 * m_A98; + m_A100 += m_A31 * f13_26; + m_A102 += m_A32 * f13_26; + m_A104 += m_A33 * f13_26; + RHS26 += f13_26 * RHS13; + const double f14 = 1.0 / m_A35; + const double f14_25 = -f14 * m_A89; + RHS25 += f14_25 * RHS14; + const double f15 = 1.0 / m_A37; + const double f15_22 = -f15 * m_A66; + m_A71 += m_A38 * f15_22; + RHS22 += f15_22 * RHS15; + const double f16 = 1.0 / m_A40; + const double f16_28 = -f16 * m_A117; + RHS28 += f16_28 * RHS16; + const double f17 = 1.0 / m_A43; + const double f17_22 = -f17 * m_A67; + m_A69 += m_A44 * f17_22; + m_A71 += m_A45 * f17_22; + RHS22 += f17_22 * RHS17; + const double f17_25 = -f17 * m_A90; + m_A91 += m_A44 * f17_25; + m_A93 += m_A45 * f17_25; + RHS25 += f17_25 * RHS17; + const double f18 = 1.0 / m_A47; + const double f18_27 = -f18 * m_A107; + m_A108 += m_A48 * f18_27; + m_A113 += m_A49 * f18_27; + m_A114 += m_A50 * f18_27; + RHS27 += f18_27 * RHS18; + const double f18_28 = -f18 * m_A118; + m_A119 += m_A48 * f18_28; + m_A120 += m_A49 * f18_28; + m_A121 += m_A50 * f18_28; + RHS28 += f18_28 * RHS18; + const double f19 = 1.0 / m_A52; + const double f19_26 = -f19 * m_A99; + RHS26 += f19_26 * RHS19; + const double f20 = 1.0 / m_A55; + const double f20_22 = -f20 * m_A68; + m_A69 += m_A56 * f20_22; + m_A70 += m_A57 * f20_22; + m_A72 += m_A58 * f20_22; + RHS22 += f20_22 * RHS20; + const double f20_24 = -f20 * m_A79; + m_A80 += m_A56 * f20_24; + m_A82 += m_A57 * f20_24; + m_A84 += m_A58 * f20_24; + RHS24 += f20_24 * RHS20; + const double f20_26 = -f20 * m_A100; + m_A101 += m_A56 * f20_26; + m_A102 += m_A57 * f20_26; + m_A104 += m_A58 * f20_26; + RHS26 += f20_26 * RHS20; + const double f21 = 1.0 / m_A60; + const double f21_27 = -f21 * m_A108; + m_A114 += m_A61 * f21_27; + RHS27 += f21_27 * RHS21; + const double f21_28 = -f21 * m_A119; + m_A121 += m_A61 * f21_28; + RHS28 += f21_28 * RHS21; + const double f22 = 1.0 / m_A69; + const double f22_24 = -f22 * m_A80; + m_A82 += m_A70 * f22_24; + m_A83 += m_A71 * f22_24; + m_A84 += m_A72 * f22_24; + m_A85 += m_A73 * f22_24; + RHS24 += f22_24 * RHS22; + const double f22_25 = -f22 * m_A91; + m_A92 += m_A70 * f22_25; + m_A93 += m_A71 * f22_25; + m_A94 += m_A72 * f22_25; + m_A95 += m_A73 * f22_25; + RHS25 += f22_25 * RHS22; + const double f22_26 = -f22 * m_A101; + m_A102 += m_A70 * f22_26; + m_A103 += m_A71 * f22_26; + m_A104 += m_A72 * f22_26; + m_A105 += m_A73 * f22_26; + RHS26 += f22_26 * RHS22; + const double f22_27 = -f22 * m_A109; + m_A110 += m_A70 * f22_27; + m_A111 += m_A71 * f22_27; + m_A112 += m_A72 * f22_27; + m_A113 += m_A73 * f22_27; + RHS27 += f22_27 * RHS22; + const double f23 = 1.0 / m_A75; + const double f23_24 = -f23 * m_A81; + m_A84 += m_A76 * f23_24; + RHS24 += f23_24 * RHS23; + const double f24 = 1.0 / m_A82; + const double f24_25 = -f24 * m_A92; + m_A93 += m_A83 * f24_25; + m_A94 += m_A84 * f24_25; + m_A95 += m_A85 * f24_25; + RHS25 += f24_25 * RHS24; + const double f24_26 = -f24 * m_A102; + m_A103 += m_A83 * f24_26; + m_A104 += m_A84 * f24_26; + m_A105 += m_A85 * f24_26; + RHS26 += f24_26 * RHS24; + const double f24_27 = -f24 * m_A110; + m_A111 += m_A83 * f24_27; + m_A112 += m_A84 * f24_27; + m_A113 += m_A85 * f24_27; + RHS27 += f24_27 * RHS24; + const double f25 = 1.0 / m_A93; + const double f25_26 = -f25 * m_A103; + m_A104 += m_A94 * f25_26; + m_A105 += m_A95 * f25_26; + RHS26 += f25_26 * RHS25; + const double f25_27 = -f25 * m_A111; + m_A112 += m_A94 * f25_27; + m_A113 += m_A95 * f25_27; + RHS27 += f25_27 * RHS25; + const double f26 = 1.0 / m_A104; + const double f26_27 = -f26 * m_A112; + m_A113 += m_A105 * f26_27; + RHS27 += f26_27 * RHS26; + const double f27 = 1.0 / m_A113; + const double f27_28 = -f27 * m_A120; + m_A121 += m_A114 * f27_28; + RHS28 += f27_28 * RHS27; + V[28] = RHS28 / m_A121; + double tmp27 = 0.0; + tmp27 += m_A114 * V[28]; + V[27] = (RHS27 - tmp27) / m_A113; + double tmp26 = 0.0; + tmp26 += m_A105 * V[27]; + V[26] = (RHS26 - tmp26) / m_A104; + double tmp25 = 0.0; + tmp25 += m_A94 * V[26]; + tmp25 += m_A95 * V[27]; + V[25] = (RHS25 - tmp25) / m_A93; + double tmp24 = 0.0; + tmp24 += m_A83 * V[25]; + tmp24 += m_A84 * V[26]; + tmp24 += m_A85 * V[27]; + V[24] = (RHS24 - tmp24) / m_A82; + double tmp23 = 0.0; + tmp23 += m_A76 * V[26]; + V[23] = (RHS23 - tmp23) / m_A75; + double tmp22 = 0.0; + tmp22 += m_A70 * V[24]; + tmp22 += m_A71 * V[25]; + tmp22 += m_A72 * V[26]; + tmp22 += m_A73 * V[27]; + V[22] = (RHS22 - tmp22) / m_A69; + double tmp21 = 0.0; + tmp21 += m_A61 * V[28]; + V[21] = (RHS21 - tmp21) / m_A60; + double tmp20 = 0.0; + tmp20 += m_A56 * V[22]; + tmp20 += m_A57 * V[24]; + tmp20 += m_A58 * V[26]; + V[20] = (RHS20 - tmp20) / m_A55; + double tmp19 = 0.0; + V[19] = (RHS19 - tmp19) / m_A52; + double tmp18 = 0.0; + tmp18 += m_A48 * V[21]; + tmp18 += m_A49 * V[27]; + tmp18 += m_A50 * V[28]; + V[18] = (RHS18 - tmp18) / m_A47; + double tmp17 = 0.0; + tmp17 += m_A44 * V[22]; + tmp17 += m_A45 * V[25]; + V[17] = (RHS17 - tmp17) / m_A43; + double tmp16 = 0.0; + V[16] = (RHS16 - tmp16) / m_A40; + double tmp15 = 0.0; + tmp15 += m_A38 * V[25]; + V[15] = (RHS15 - tmp15) / m_A37; + double tmp14 = 0.0; + V[14] = (RHS14 - tmp14) / m_A35; + double tmp13 = 0.0; + tmp13 += m_A31 * V[20]; + tmp13 += m_A32 * V[24]; + tmp13 += m_A33 * V[26]; + V[13] = (RHS13 - tmp13) / m_A30; + double tmp12 = 0.0; + tmp12 += m_A29 * V[26]; + V[12] = (RHS12 - tmp12) / m_A28; + double tmp11 = 0.0; + tmp11 += m_A27 * V[23]; + V[11] = (RHS11 - tmp11) / m_A26; + double tmp10 = 0.0; + tmp10 += m_A24 * V[20]; + tmp10 += m_A25 * V[22]; + V[10] = (RHS10 - tmp10) / m_A23; + double tmp9 = 0.0; + tmp9 += m_A22 * V[19]; + V[9] = (RHS9 - tmp9) / m_A21; + double tmp8 = 0.0; + tmp8 += m_A20 * V[28]; + V[8] = (RHS8 - tmp8) / m_A19; + double tmp7 = 0.0; + tmp7 += m_A17 * V[22]; + tmp7 += m_A18 * V[27]; + V[7] = (RHS7 - tmp7) / m_A16; + double tmp6 = 0.0; + tmp6 += m_A15 * V[21]; + V[6] = (RHS6 - tmp6) / m_A14; + double tmp5 = 0.0; + tmp5 += m_A11 * V[17]; + tmp5 += m_A12 * V[22]; + tmp5 += m_A13 * V[25]; + V[5] = (RHS5 - tmp5) / m_A10; + double tmp4 = 0.0; + tmp4 += m_A9 * V[16]; + V[4] = (RHS4 - tmp4) / m_A8; + double tmp3 = 0.0; + tmp3 += m_A7 * V[15]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[25]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[14]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[17]; + V[0] = (RHS0 - tmp0) / m_A0; +} + +// sspeedr,280zzzap +static void nl_gcr_123_double_double_864a61c57bac9c38(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + double m_A54(0.0); + double m_A55(0.0); + double m_A56(0.0); + double m_A57(0.0); + double m_A58(0.0); + double m_A59(0.0); + double m_A60(0.0); + double m_A61(0.0); + double m_A62(0.0); + double m_A63(0.0); + double m_A64(0.0); + double m_A65(0.0); + double m_A66(0.0); + double m_A67(0.0); + double m_A68(0.0); + double m_A69(0.0); + double m_A70(0.0); + double m_A71(0.0); + double m_A72(0.0); + double m_A73(0.0); + double m_A74(0.0); + double m_A75(0.0); + double m_A76(0.0); + double m_A77(0.0); + double m_A78(0.0); + double m_A79(0.0); + double m_A80(0.0); + double m_A81(0.0); + double m_A82(0.0); + double m_A83(0.0); + double m_A84(0.0); + double m_A85(0.0); + double m_A86(0.0); + double m_A87(0.0); + double m_A88(0.0); + double m_A89(0.0); + double m_A90(0.0); + double m_A91(0.0); + double m_A92(0.0); + double m_A93(0.0); + double m_A94(0.0); + double m_A95(0.0); + double m_A96(0.0); + double m_A97(0.0); + double m_A98(0.0); + double m_A99(0.0); + double m_A100(0.0); + double m_A101(0.0); + double m_A102(0.0); + double m_A103(0.0); + double m_A104(0.0); + double m_A105(0.0); + double m_A106(0.0); + double m_A107(0.0); + double m_A108(0.0); + double m_A109(0.0); + double m_A110(0.0); + double m_A111(0.0); + double m_A112(0.0); + double m_A113(0.0); + double m_A114(0.0); + double m_A115(0.0); + double m_A116(0.0); + double m_A117(0.0); + double m_A118(0.0); + double m_A119(0.0); + double m_A120(0.0); + double m_A121(0.0); + double m_A122(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 -= go[4] * *cnV[4]; + m_A4 += gt[5]; + m_A4 += gt[6]; + m_A4 += gt[7]; + m_A4 += gt[8]; + m_A4 += gt[9]; + m_A4 += gt[10]; + m_A4 += gt[11]; + m_A5 += go[5]; + double RHS2 = Idr[5]; + RHS2 += Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 += Idr[11]; + RHS2 -= go[6] * *cnV[6]; + RHS2 -= go[7] * *cnV[7]; + RHS2 -= go[8] * *cnV[8]; + RHS2 -= go[9] * *cnV[9]; + RHS2 -= go[10] * *cnV[10]; + RHS2 -= go[11] * *cnV[11]; + m_A6 += gt[12]; + m_A6 += gt[13]; + m_A6 += gt[14]; + m_A7 += go[12]; + double RHS3 = Idr[12]; + RHS3 += Idr[13]; + RHS3 += Idr[14]; + RHS3 -= go[13] * *cnV[13]; + RHS3 -= go[14] * *cnV[14]; + m_A8 += gt[15]; + m_A8 += gt[16]; + m_A8 += gt[17]; + m_A8 += gt[18]; + m_A8 += gt[19]; + m_A8 += gt[20]; + m_A8 += gt[21]; + m_A9 += go[15]; + double RHS4 = Idr[15]; + RHS4 += Idr[16]; + RHS4 += Idr[17]; + RHS4 += Idr[18]; + RHS4 += Idr[19]; + RHS4 += Idr[20]; + RHS4 += Idr[21]; + RHS4 -= go[16] * *cnV[16]; + RHS4 -= go[17] * *cnV[17]; + RHS4 -= go[18] * *cnV[18]; + RHS4 -= go[19] * *cnV[19]; + RHS4 -= go[20] * *cnV[20]; + RHS4 -= go[21] * *cnV[21]; + m_A10 += gt[22]; + m_A10 += gt[23]; + m_A11 += go[22]; + double RHS5 = Idr[22]; + RHS5 += Idr[23]; + RHS5 -= go[23] * *cnV[23]; + m_A12 += gt[24]; + m_A12 += gt[25]; + m_A14 += go[24]; + m_A13 += go[25]; + double RHS6 = Idr[24]; + RHS6 += Idr[25]; + m_A15 += gt[26]; + m_A15 += gt[27]; + m_A16 += go[26]; + double RHS7 = Idr[26]; + RHS7 += Idr[27]; + RHS7 -= go[27] * *cnV[27]; + m_A17 += gt[28]; + m_A17 += gt[29]; + m_A18 += go[28]; + double RHS8 = Idr[28]; + RHS8 += Idr[29]; + RHS8 -= go[29] * *cnV[29]; + m_A19 += gt[30]; + m_A19 += gt[31]; + m_A19 += gt[32]; + m_A19 += gt[33]; + m_A19 += gt[34]; + m_A19 += gt[35]; + m_A19 += gt[36]; + m_A20 += go[30]; + double RHS9 = Idr[30]; + RHS9 += Idr[31]; + RHS9 += Idr[32]; + RHS9 += Idr[33]; + RHS9 += Idr[34]; + RHS9 += Idr[35]; + RHS9 += Idr[36]; + RHS9 -= go[31] * *cnV[31]; + RHS9 -= go[32] * *cnV[32]; + RHS9 -= go[33] * *cnV[33]; + RHS9 -= go[34] * *cnV[34]; + RHS9 -= go[35] * *cnV[35]; + RHS9 -= go[36] * *cnV[36]; + m_A21 += gt[37]; + m_A21 += gt[38]; + m_A21 += gt[39]; + m_A22 += go[37]; + double RHS10 = Idr[37]; + RHS10 += Idr[38]; + RHS10 += Idr[39]; + RHS10 -= go[38] * *cnV[38]; + RHS10 -= go[39] * *cnV[39]; + m_A23 += gt[40]; + m_A23 += gt[41]; + m_A23 += gt[42]; + m_A23 += gt[43]; + m_A24 += go[40]; + double RHS11 = Idr[40]; + RHS11 += Idr[41]; + RHS11 += Idr[42]; + RHS11 += Idr[43]; + RHS11 -= go[41] * *cnV[41]; + RHS11 -= go[42] * *cnV[42]; + RHS11 -= go[43] * *cnV[43]; + m_A25 += gt[44]; + m_A25 += gt[45]; + m_A25 += gt[46]; + m_A25 += gt[47]; + m_A25 += gt[48]; + m_A25 += gt[49]; + m_A25 += gt[50]; + m_A26 += go[44]; + double RHS12 = Idr[44]; + RHS12 += Idr[45]; + RHS12 += Idr[46]; + RHS12 += Idr[47]; + RHS12 += Idr[48]; + RHS12 += Idr[49]; + RHS12 += Idr[50]; + RHS12 -= go[45] * *cnV[45]; + RHS12 -= go[46] * *cnV[46]; + RHS12 -= go[47] * *cnV[47]; + RHS12 -= go[48] * *cnV[48]; + RHS12 -= go[49] * *cnV[49]; + RHS12 -= go[50] * *cnV[50]; + m_A27 += gt[51]; + m_A27 += gt[52]; + m_A28 += go[51]; + double RHS13 = Idr[51]; + RHS13 += Idr[52]; + RHS13 -= go[52] * *cnV[52]; + m_A29 += gt[53]; + m_A29 += gt[54]; + m_A30 += go[53]; + double RHS14 = Idr[53]; + RHS14 += Idr[54]; + RHS14 -= go[54] * *cnV[54]; + m_A31 += gt[55]; + m_A31 += gt[56]; + m_A32 += go[55]; + double RHS15 = Idr[55]; + RHS15 += Idr[56]; + RHS15 -= go[56] * *cnV[56]; + m_A33 += gt[57]; + m_A33 += gt[58]; + m_A33 += gt[59]; + m_A33 += gt[60]; + m_A35 += go[57]; + m_A34 += go[58]; + double RHS16 = Idr[57]; + RHS16 += Idr[58]; + RHS16 += Idr[59]; + RHS16 += Idr[60]; + RHS16 -= go[59] * *cnV[59]; + RHS16 -= go[60] * *cnV[60]; + m_A36 += gt[61]; + m_A36 += gt[62]; + m_A36 += gt[63]; + m_A37 += go[61]; + double RHS17 = Idr[61]; + RHS17 += Idr[62]; + RHS17 += Idr[63]; + RHS17 -= go[62] * *cnV[62]; + RHS17 -= go[63] * *cnV[63]; + m_A38 += gt[64]; + m_A38 += gt[65]; + m_A39 += go[64]; + double RHS18 = Idr[64]; + RHS18 += Idr[65]; + RHS18 -= go[65] * *cnV[65]; + m_A40 += gt[66]; + m_A40 += gt[67]; + m_A41 += go[66]; + double RHS19 = Idr[66]; + RHS19 += Idr[67]; + RHS19 -= go[67] * *cnV[67]; + m_A43 += gt[68]; + m_A43 += gt[69]; + m_A43 += gt[70]; + m_A43 += gt[71]; + m_A42 += go[68]; + double RHS20 = Idr[68]; + RHS20 += Idr[69]; + RHS20 += Idr[70]; + RHS20 += Idr[71]; + RHS20 -= go[69] * *cnV[69]; + RHS20 -= go[70] * *cnV[70]; + RHS20 -= go[71] * *cnV[71]; + m_A47 += gt[72]; + m_A47 += gt[73]; + m_A46 += go[72]; + m_A45 += go[73]; + double RHS21 = Idr[72]; + RHS21 += Idr[73]; + m_A51 += gt[74]; + m_A51 += gt[75]; + m_A49 += go[74]; + double RHS22 = Idr[74]; + RHS22 += Idr[75]; + RHS22 -= go[75] * *cnV[75]; + m_A54 += gt[76]; + m_A54 += gt[77]; + m_A54 += gt[78]; + m_A53 += go[76]; + m_A52 += go[77]; + double RHS23 = Idr[76]; + RHS23 += Idr[77]; + RHS23 += Idr[78]; + RHS23 -= go[78] * *cnV[78]; + m_A56 += gt[79]; + m_A56 += gt[80]; + m_A56 += gt[81]; + m_A56 += gt[82]; + m_A55 += go[79]; + m_A57 += go[80]; + double RHS24 = Idr[79]; + RHS24 += Idr[80]; + RHS24 += Idr[81]; + RHS24 += Idr[82]; + RHS24 -= go[81] * *cnV[81]; + RHS24 -= go[82] * *cnV[82]; + m_A59 += gt[83]; + m_A59 += gt[84]; + m_A59 += gt[85]; + m_A59 += gt[86]; + m_A58 += go[83]; + m_A60 += go[84]; + double RHS25 = Idr[83]; + RHS25 += Idr[84]; + RHS25 += Idr[85]; + RHS25 += Idr[86]; + RHS25 -= go[85] * *cnV[85]; + RHS25 -= go[86] * *cnV[86]; + m_A62 += gt[87]; + m_A62 += gt[88]; + m_A63 += go[87]; + m_A61 += go[88]; + double RHS26 = Idr[87]; + RHS26 += Idr[88]; + m_A67 += gt[89]; + m_A67 += gt[90]; + m_A67 += gt[91]; + m_A67 += gt[92]; + m_A67 += gt[93]; + m_A67 += gt[94]; + m_A64 += go[89]; + m_A65 += go[90]; + m_A69 += go[91]; + m_A68 += go[92]; + double RHS27 = Idr[89]; + RHS27 += Idr[90]; + RHS27 += Idr[91]; + RHS27 += Idr[92]; + RHS27 += Idr[93]; + RHS27 += Idr[94]; + RHS27 -= go[93] * *cnV[93]; + RHS27 -= go[94] * *cnV[94]; + m_A72 += gt[95]; + m_A72 += gt[96]; + m_A72 += gt[97]; + m_A72 += gt[98]; + m_A71 += go[95]; + m_A73 += go[96]; + double RHS28 = Idr[95]; + RHS28 += Idr[96]; + RHS28 += Idr[97]; + RHS28 += Idr[98]; + RHS28 -= go[97] * *cnV[97]; + RHS28 -= go[98] * *cnV[98]; + m_A76 += gt[99]; + m_A76 += gt[100]; + m_A76 += gt[101]; + m_A76 += gt[102]; + m_A77 += go[99]; + m_A78 += go[100]; + m_A74 += go[101]; + m_A75 += go[102]; + double RHS29 = Idr[99]; + RHS29 += Idr[100]; + RHS29 += Idr[101]; + RHS29 += Idr[102]; + m_A81 += gt[103]; + m_A81 += gt[104]; + m_A81 += gt[105]; + m_A80 += go[103]; + m_A79 += go[104]; + double RHS30 = Idr[103]; + RHS30 += Idr[104]; + RHS30 += Idr[105]; + RHS30 -= go[105] * *cnV[105]; + m_A84 += gt[106]; + m_A84 += gt[107]; + m_A82 += go[106]; + m_A83 += go[107]; + double RHS31 = Idr[106]; + RHS31 += Idr[107]; + m_A91 += gt[108]; + m_A91 += gt[109]; + m_A91 += gt[110]; + m_A91 += gt[111]; + m_A91 += gt[112]; + m_A86 += go[108]; + m_A90 += go[109]; + m_A88 += go[110]; + m_A85 += go[111]; + m_A87 += go[112]; + double RHS32 = Idr[108]; + RHS32 += Idr[109]; + RHS32 += Idr[110]; + RHS32 += Idr[111]; + RHS32 += Idr[112]; + m_A99 += gt[113]; + m_A99 += gt[114]; + m_A99 += gt[115]; + m_A99 += gt[116]; + m_A99 += gt[117]; + m_A96 += go[113]; + m_A100 += go[114]; + m_A97 += go[115]; + m_A94 += go[116]; + m_A95 += go[117]; + double RHS33 = Idr[113]; + RHS33 += Idr[114]; + RHS33 += Idr[115]; + RHS33 += Idr[116]; + RHS33 += Idr[117]; + m_A106 += gt[118]; + m_A106 += gt[119]; + m_A106 += gt[120]; + m_A106 += gt[121]; + m_A103 += go[118]; + m_A104 += go[119]; + m_A101 += go[120]; + m_A102 += go[121]; + double RHS34 = Idr[118]; + RHS34 += Idr[119]; + RHS34 += Idr[120]; + RHS34 += Idr[121]; + m_A111 += gt[122]; + m_A111 += gt[123]; + m_A111 += gt[124]; + m_A111 += gt[125]; + m_A108 += go[122]; + m_A109 += go[123]; + double RHS35 = Idr[122]; + RHS35 += Idr[123]; + RHS35 += Idr[124]; + RHS35 += Idr[125]; + RHS35 -= go[124] * *cnV[124]; + RHS35 -= go[125] * *cnV[125]; + m_A122 += gt[126]; + m_A122 += gt[127]; + m_A122 += gt[128]; + m_A122 += gt[129]; + m_A122 += gt[130]; + m_A122 += gt[131]; + m_A113 += go[126]; + m_A117 += go[127]; + m_A120 += go[128]; + m_A114 += go[129]; + double RHS36 = Idr[126]; + RHS36 += Idr[127]; + RHS36 += Idr[128]; + RHS36 += Idr[129]; + RHS36 += Idr[130]; + RHS36 += Idr[131]; + RHS36 -= go[130] * *cnV[130]; + RHS36 -= go[131] * *cnV[131]; + const double f0 = 1.0 / m_A0; + const double f0_24 = -f0 * m_A55; + m_A57 += m_A1 * f0_24; + RHS24 += f0_24 * RHS0; + const double f0_32 = -f0 * m_A85; + m_A91 += m_A1 * f0_32; + RHS32 += f0_32 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_32 = -f1 * m_A86; + m_A91 += m_A3 * f1_32; + RHS32 += f1_32 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_27 = -f2 * m_A64; + m_A66 += m_A5 * f2_27; + RHS27 += f2_27 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_25 = -f3 * m_A58; + m_A60 += m_A7 * f3_25; + RHS25 += f3_25 * RHS3; + const double f3_34 = -f3 * m_A101; + m_A106 += m_A7 * f3_34; + RHS34 += f3_34 * RHS3; + const double f4 = 1.0 / m_A8; + const double f4_20 = -f4 * m_A42; + m_A44 += m_A9 * f4_20; + RHS20 += f4_20 * RHS4; + const double f5 = 1.0 / m_A10; + const double f5_21 = -f5 * m_A45; + m_A47 += m_A11 * f5_21; + RHS21 += f5_21 * RHS5; + const double f5_32 = -f5 * m_A87; + m_A88 += m_A11 * f5_32; + RHS32 += f5_32 * RHS5; + const double f6 = 1.0 / m_A12; + const double f6_21 = -f6 * m_A46; + m_A47 += m_A13 * f6_21; + m_A48 += m_A14 * f6_21; + RHS21 += f6_21 * RHS6; + const double f6_22 = -f6 * m_A49; + m_A50 += m_A13 * f6_22; + m_A51 += m_A14 * f6_22; + RHS22 += f6_22 * RHS6; + const double f7 = 1.0 / m_A15; + const double f7_23 = -f7 * m_A52; + m_A54 += m_A16 * f7_23; + RHS23 += f7_23 * RHS7; + const double f7_34 = -f7 * m_A102; + m_A103 += m_A16 * f7_34; + RHS34 += f7_34 * RHS7; + const double f8 = 1.0 / m_A17; + const double f8_23 = -f8 * m_A53; + m_A54 += m_A18 * f8_23; + RHS23 += f8_23 * RHS8; + const double f9 = 1.0 / m_A19; + const double f9_36 = -f9 * m_A113; + m_A116 += m_A20 * f9_36; + RHS36 += f9_36 * RHS9; + const double f10 = 1.0 / m_A21; + const double f10_28 = -f10 * m_A71; + m_A73 += m_A22 * f10_28; + RHS28 += f10_28 * RHS10; + const double f10_33 = -f10 * m_A94; + m_A99 += m_A22 * f10_33; + RHS33 += f10_33 * RHS10; + const double f13 = 1.0 / m_A27; + const double f13_26 = -f13 * m_A61; + m_A62 += m_A28 * f13_26; + RHS26 += f13_26 * RHS13; + const double f13_33 = -f13 * m_A95; + m_A97 += m_A28 * f13_33; + RHS33 += f13_33 * RHS13; + const double f14 = 1.0 / m_A29; + const double f14_33 = -f14 * m_A96; + m_A99 += m_A30 * f14_33; + RHS33 += f14_33 * RHS14; + const double f15 = 1.0 / m_A31; + const double f15_31 = -f15 * m_A82; + m_A84 += m_A32 * f15_31; + RHS31 += f15_31 * RHS15; + const double f16 = 1.0 / m_A33; + const double f16_27 = -f16 * m_A65; + m_A67 += m_A34 * f16_27; + m_A70 += m_A35 * f16_27; + RHS27 += f16_27 * RHS16; + const double f16_36 = -f16 * m_A114; + m_A115 += m_A34 * f16_36; + m_A122 += m_A35 * f16_36; + RHS36 += f16_36 * RHS16; + const double f17 = 1.0 / m_A36; + const double f17_29 = -f17 * m_A74; + m_A76 += m_A37 * f17_29; + RHS29 += f17_29 * RHS17; + const double f17_35 = -f17 * m_A108; + m_A109 += m_A37 * f17_35; + RHS35 += f17_35 * RHS17; + const double f18 = 1.0 / m_A38; + const double f18_29 = -f18 * m_A75; + m_A77 += m_A39 * f18_29; + RHS29 += f18_29 * RHS18; + const double f18_30 = -f18 * m_A79; + m_A81 += m_A39 * f18_30; + RHS30 += f18_30 * RHS18; + const double f19 = 1.0 / m_A40; + const double f19_30 = -f19 * m_A80; + m_A81 += m_A41 * f19_30; + RHS30 += f19_30 * RHS19; + const double f21 = 1.0 / m_A47; + const double f21_22 = -f21 * m_A50; + m_A51 += m_A48 * f21_22; + RHS22 += f21_22 * RHS21; + const double f21_32 = -f21 * m_A88; + m_A89 += m_A48 * f21_32; + RHS32 += f21_32 * RHS21; + const double f22 = 1.0 / m_A51; + const double f22_32 = -f22 * m_A89; + RHS32 += f22_32 * RHS22; + const double f23 = 1.0 / m_A54; + const double f23_34 = -f23 * m_A103; + RHS34 += f23_34 * RHS23; + const double f24 = 1.0 / m_A56; + const double f24_27 = -f24 * m_A66; + m_A68 += m_A57 * f24_27; + RHS27 += f24_27 * RHS24; + const double f26 = 1.0 / m_A62; + const double f26_31 = -f26 * m_A83; + m_A84 += m_A63 * f26_31; + RHS31 += f26_31 * RHS26; + const double f26_33 = -f26 * m_A97; + m_A98 += m_A63 * f26_33; + RHS33 += f26_33 * RHS26; + const double f27 = 1.0 / m_A67; + const double f27_32 = -f27 * m_A90; + m_A91 += m_A68 * f27_32; + m_A92 += m_A69 * f27_32; + m_A93 += m_A70 * f27_32; + RHS32 += f27_32 * RHS27; + const double f27_34 = -f27 * m_A104; + m_A105 += m_A68 * f27_34; + m_A106 += m_A69 * f27_34; + m_A107 += m_A70 * f27_34; + RHS34 += f27_34 * RHS27; + const double f27_36 = -f27 * m_A115; + m_A119 += m_A68 * f27_36; + m_A121 += m_A69 * f27_36; + m_A122 += m_A70 * f27_36; + RHS36 += f27_36 * RHS27; + const double f28 = 1.0 / m_A72; + const double f28_36 = -f28 * m_A116; + m_A120 += m_A73 * f28_36; + RHS36 += f28_36 * RHS28; + const double f29 = 1.0 / m_A76; + const double f29_35 = -f29 * m_A109; + m_A110 += m_A77 * f29_35; + m_A112 += m_A78 * f29_35; + RHS35 += f29_35 * RHS29; + const double f29_36 = -f29 * m_A117; + m_A118 += m_A77 * f29_36; + m_A122 += m_A78 * f29_36; + RHS36 += f29_36 * RHS29; + const double f30 = 1.0 / m_A81; + const double f30_35 = -f30 * m_A110; + RHS35 += f30_35 * RHS30; + const double f30_36 = -f30 * m_A118; + RHS36 += f30_36 * RHS30; + const double f31 = 1.0 / m_A84; + const double f31_33 = -f31 * m_A98; + RHS33 += f31_33 * RHS31; + const double f32 = 1.0 / m_A91; + const double f32_34 = -f32 * m_A105; + m_A106 += m_A92 * f32_34; + m_A107 += m_A93 * f32_34; + RHS34 += f32_34 * RHS32; + const double f32_36 = -f32 * m_A119; + m_A121 += m_A92 * f32_36; + m_A122 += m_A93 * f32_36; + RHS36 += f32_36 * RHS32; + const double f33 = 1.0 / m_A99; + const double f33_36 = -f33 * m_A120; + m_A122 += m_A100 * f33_36; + RHS36 += f33_36 * RHS33; + const double f34 = 1.0 / m_A106; + const double f34_36 = -f34 * m_A121; + m_A122 += m_A107 * f34_36; + RHS36 += f34_36 * RHS34; + V[36] = RHS36 / m_A122; + double tmp35 = 0.0; + tmp35 += m_A112 * V[36]; + V[35] = (RHS35 - tmp35) / m_A111; + double tmp34 = 0.0; + tmp34 += m_A107 * V[36]; + V[34] = (RHS34 - tmp34) / m_A106; + double tmp33 = 0.0; + tmp33 += m_A100 * V[36]; + V[33] = (RHS33 - tmp33) / m_A99; + double tmp32 = 0.0; + tmp32 += m_A92 * V[34]; + tmp32 += m_A93 * V[36]; + V[32] = (RHS32 - tmp32) / m_A91; + double tmp31 = 0.0; + V[31] = (RHS31 - tmp31) / m_A84; + double tmp30 = 0.0; + V[30] = (RHS30 - tmp30) / m_A81; + double tmp29 = 0.0; + tmp29 += m_A77 * V[30]; + tmp29 += m_A78 * V[36]; + V[29] = (RHS29 - tmp29) / m_A76; + double tmp28 = 0.0; + tmp28 += m_A73 * V[33]; + V[28] = (RHS28 - tmp28) / m_A72; + double tmp27 = 0.0; + tmp27 += m_A68 * V[32]; + tmp27 += m_A69 * V[34]; + tmp27 += m_A70 * V[36]; + V[27] = (RHS27 - tmp27) / m_A67; + double tmp26 = 0.0; + tmp26 += m_A63 * V[31]; + V[26] = (RHS26 - tmp26) / m_A62; + double tmp25 = 0.0; + tmp25 += m_A60 * V[34]; + V[25] = (RHS25 - tmp25) / m_A59; + double tmp24 = 0.0; + tmp24 += m_A57 * V[32]; + V[24] = (RHS24 - tmp24) / m_A56; + double tmp23 = 0.0; + V[23] = (RHS23 - tmp23) / m_A54; + double tmp22 = 0.0; + V[22] = (RHS22 - tmp22) / m_A51; + double tmp21 = 0.0; + tmp21 += m_A48 * V[22]; + V[21] = (RHS21 - tmp21) / m_A47; + double tmp20 = 0.0; + tmp20 += m_A44 * V[25]; + V[20] = (RHS20 - tmp20) / m_A43; + double tmp19 = 0.0; + tmp19 += m_A41 * V[30]; + V[19] = (RHS19 - tmp19) / m_A40; + double tmp18 = 0.0; + tmp18 += m_A39 * V[30]; + V[18] = (RHS18 - tmp18) / m_A38; + double tmp17 = 0.0; + tmp17 += m_A37 * V[29]; + V[17] = (RHS17 - tmp17) / m_A36; + double tmp16 = 0.0; + tmp16 += m_A34 * V[27]; + tmp16 += m_A35 * V[36]; + V[16] = (RHS16 - tmp16) / m_A33; + double tmp15 = 0.0; + tmp15 += m_A32 * V[31]; + V[15] = (RHS15 - tmp15) / m_A31; + double tmp14 = 0.0; + tmp14 += m_A30 * V[33]; + V[14] = (RHS14 - tmp14) / m_A29; + double tmp13 = 0.0; + tmp13 += m_A28 * V[26]; + V[13] = (RHS13 - tmp13) / m_A27; + double tmp12 = 0.0; + tmp12 += m_A26 * V[35]; + V[12] = (RHS12 - tmp12) / m_A25; + double tmp11 = 0.0; + tmp11 += m_A24 * V[12]; + V[11] = (RHS11 - tmp11) / m_A23; + double tmp10 = 0.0; + tmp10 += m_A22 * V[33]; + V[10] = (RHS10 - tmp10) / m_A21; + double tmp9 = 0.0; + tmp9 += m_A20 * V[28]; + V[9] = (RHS9 - tmp9) / m_A19; + double tmp8 = 0.0; + tmp8 += m_A18 * V[23]; + V[8] = (RHS8 - tmp8) / m_A17; + double tmp7 = 0.0; + tmp7 += m_A16 * V[23]; + V[7] = (RHS7 - tmp7) / m_A15; + double tmp6 = 0.0; + tmp6 += m_A13 * V[21]; + tmp6 += m_A14 * V[22]; + V[6] = (RHS6 - tmp6) / m_A12; + double tmp5 = 0.0; + tmp5 += m_A11 * V[21]; + V[5] = (RHS5 - tmp5) / m_A10; + double tmp4 = 0.0; + tmp4 += m_A9 * V[25]; + V[4] = (RHS4 - tmp4) / m_A8; + double tmp3 = 0.0; + tmp3 += m_A7 * V[34]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[24]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[32]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[32]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // sspeedr static void nl_gcr_13_double_double_3e833834e5ce5aee(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -60774,6 +61788,398 @@ static void nl_gcr_176_double_double_2294220d3c91e762(double * __restrict V, con V[0] = (RHS0 - tmp0) / m_A0; } +// sspeedr,280zzzap +static void nl_gcr_57_double_double_bb501e6a23177009(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + double m_A12(0.0); + double m_A13(0.0); + double m_A14(0.0); + double m_A15(0.0); + double m_A16(0.0); + double m_A17(0.0); + double m_A18(0.0); + double m_A19(0.0); + double m_A20(0.0); + double m_A21(0.0); + double m_A22(0.0); + double m_A23(0.0); + double m_A24(0.0); + double m_A25(0.0); + double m_A26(0.0); + double m_A27(0.0); + double m_A28(0.0); + double m_A29(0.0); + double m_A30(0.0); + double m_A31(0.0); + double m_A32(0.0); + double m_A33(0.0); + double m_A34(0.0); + double m_A35(0.0); + double m_A36(0.0); + double m_A37(0.0); + double m_A38(0.0); + double m_A39(0.0); + double m_A40(0.0); + double m_A41(0.0); + double m_A42(0.0); + double m_A43(0.0); + double m_A44(0.0); + double m_A45(0.0); + double m_A46(0.0); + double m_A47(0.0); + double m_A48(0.0); + double m_A49(0.0); + double m_A50(0.0); + double m_A51(0.0); + double m_A52(0.0); + double m_A53(0.0); + double m_A54(0.0); + double m_A55(0.0); + double m_A56(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A0 += gt[2]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 += Idr[2]; + RHS0 -= go[1] * *cnV[1]; + RHS0 -= go[2] * *cnV[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A3 += go[3]; + double RHS1 = Idr[3]; + RHS1 += Idr[4]; + RHS1 -= go[4] * *cnV[4]; + m_A4 += gt[5]; + m_A4 += gt[6]; + m_A4 += gt[7]; + m_A4 += gt[8]; + m_A4 += gt[9]; + m_A4 += gt[10]; + m_A4 += gt[11]; + m_A5 += go[5]; + double RHS2 = Idr[5]; + RHS2 += Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 += Idr[11]; + RHS2 -= go[6] * *cnV[6]; + RHS2 -= go[7] * *cnV[7]; + RHS2 -= go[8] * *cnV[8]; + RHS2 -= go[9] * *cnV[9]; + RHS2 -= go[10] * *cnV[10]; + RHS2 -= go[11] * *cnV[11]; + m_A6 += gt[12]; + m_A6 += gt[13]; + m_A6 += gt[14]; + m_A7 += go[12]; + double RHS3 = Idr[12]; + RHS3 += Idr[13]; + RHS3 += Idr[14]; + RHS3 -= go[13] * *cnV[13]; + RHS3 -= go[14] * *cnV[14]; + m_A8 += gt[15]; + m_A8 += gt[16]; + m_A8 += gt[17]; + m_A8 += gt[18]; + m_A8 += gt[19]; + m_A8 += gt[20]; + m_A8 += gt[21]; + m_A9 += go[15]; + double RHS4 = Idr[15]; + RHS4 += Idr[16]; + RHS4 += Idr[17]; + RHS4 += Idr[18]; + RHS4 += Idr[19]; + RHS4 += Idr[20]; + RHS4 += Idr[21]; + RHS4 -= go[16] * *cnV[16]; + RHS4 -= go[17] * *cnV[17]; + RHS4 -= go[18] * *cnV[18]; + RHS4 -= go[19] * *cnV[19]; + RHS4 -= go[20] * *cnV[20]; + RHS4 -= go[21] * *cnV[21]; + m_A10 += gt[22]; + m_A10 += gt[23]; + m_A11 += go[22]; + double RHS5 = Idr[22]; + RHS5 += Idr[23]; + RHS5 -= go[23] * *cnV[23]; + m_A12 += gt[24]; + m_A12 += gt[25]; + m_A14 += go[24]; + m_A13 += go[25]; + double RHS6 = Idr[24]; + RHS6 += Idr[25]; + m_A15 += gt[26]; + m_A15 += gt[27]; + m_A16 += go[26]; + double RHS7 = Idr[26]; + RHS7 += Idr[27]; + RHS7 -= go[27] * *cnV[27]; + m_A17 += gt[28]; + m_A17 += gt[29]; + m_A18 += go[28]; + double RHS8 = Idr[28]; + RHS8 += Idr[29]; + RHS8 -= go[29] * *cnV[29]; + m_A20 += gt[30]; + m_A20 += gt[31]; + m_A20 += gt[32]; + m_A20 += gt[33]; + m_A19 += go[30]; + double RHS9 = Idr[30]; + RHS9 += Idr[31]; + RHS9 += Idr[32]; + RHS9 += Idr[33]; + RHS9 -= go[31] * *cnV[31]; + RHS9 -= go[32] * *cnV[32]; + RHS9 -= go[33] * *cnV[33]; + m_A24 += gt[34]; + m_A24 += gt[35]; + m_A23 += go[34]; + m_A22 += go[35]; + double RHS10 = Idr[34]; + RHS10 += Idr[35]; + m_A27 += gt[36]; + m_A27 += gt[37]; + m_A27 += gt[38]; + m_A27 += gt[39]; + m_A26 += go[36]; + m_A28 += go[37]; + double RHS11 = Idr[36]; + RHS11 += Idr[37]; + RHS11 += Idr[38]; + RHS11 += Idr[39]; + RHS11 -= go[38] * *cnV[38]; + RHS11 -= go[39] * *cnV[39]; + m_A31 += gt[40]; + m_A31 += gt[41]; + m_A31 += gt[42]; + m_A31 += gt[43]; + m_A31 += gt[44]; + m_A31 += gt[45]; + m_A29 += go[40]; + m_A33 += go[41]; + m_A32 += go[42]; + double RHS12 = Idr[40]; + RHS12 += Idr[41]; + RHS12 += Idr[42]; + RHS12 += Idr[43]; + RHS12 += Idr[44]; + RHS12 += Idr[45]; + RHS12 -= go[43] * *cnV[43]; + RHS12 -= go[44] * *cnV[44]; + RHS12 -= go[45] * *cnV[45]; + m_A36 += gt[46]; + m_A36 += gt[47]; + m_A34 += go[46]; + double RHS13 = Idr[46]; + RHS13 += Idr[47]; + RHS13 -= go[47] * *cnV[47]; + m_A39 += gt[48]; + m_A39 += gt[49]; + m_A39 += gt[50]; + m_A38 += go[48]; + m_A37 += go[49]; + double RHS14 = Idr[48]; + RHS14 += Idr[49]; + RHS14 += Idr[50]; + RHS14 -= go[50] * *cnV[50]; + m_A41 += gt[51]; + m_A41 += gt[52]; + m_A41 += gt[53]; + m_A41 += gt[54]; + m_A40 += go[51]; + m_A42 += go[52]; + double RHS15 = Idr[51]; + RHS15 += Idr[52]; + RHS15 += Idr[53]; + RHS15 += Idr[54]; + RHS15 -= go[53] * *cnV[53]; + RHS15 -= go[54] * *cnV[54]; + m_A49 += gt[55]; + m_A49 += gt[56]; + m_A49 += gt[57]; + m_A49 += gt[58]; + m_A49 += gt[59]; + m_A44 += go[55]; + m_A47 += go[56]; + m_A46 += go[57]; + m_A43 += go[58]; + m_A45 += go[59]; + double RHS16 = Idr[55]; + RHS16 += Idr[56]; + RHS16 += Idr[57]; + RHS16 += Idr[58]; + RHS16 += Idr[59]; + m_A56 += gt[60]; + m_A56 += gt[61]; + m_A56 += gt[62]; + m_A56 += gt[63]; + m_A54 += go[60]; + m_A53 += go[61]; + m_A51 += go[62]; + m_A52 += go[63]; + double RHS17 = Idr[60]; + RHS17 += Idr[61]; + RHS17 += Idr[62]; + RHS17 += Idr[63]; + const double f0 = 1.0 / m_A0; + const double f0_11 = -f0 * m_A26; + m_A28 += m_A1 * f0_11; + RHS11 += f0_11 * RHS0; + const double f0_16 = -f0 * m_A43; + m_A49 += m_A1 * f0_16; + RHS16 += f0_16 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_16 = -f1 * m_A44; + m_A49 += m_A3 * f1_16; + RHS16 += f1_16 * RHS1; + const double f2 = 1.0 / m_A4; + const double f2_12 = -f2 * m_A29; + m_A30 += m_A5 * f2_12; + RHS12 += f2_12 * RHS2; + const double f3 = 1.0 / m_A6; + const double f3_15 = -f3 * m_A40; + m_A42 += m_A7 * f3_15; + RHS15 += f3_15 * RHS3; + const double f3_17 = -f3 * m_A51; + m_A56 += m_A7 * f3_17; + RHS17 += f3_17 * RHS3; + const double f4 = 1.0 / m_A8; + const double f4_9 = -f4 * m_A19; + m_A21 += m_A9 * f4_9; + RHS9 += f4_9 * RHS4; + const double f5 = 1.0 / m_A10; + const double f5_10 = -f5 * m_A22; + m_A24 += m_A11 * f5_10; + RHS10 += f5_10 * RHS5; + const double f5_16 = -f5 * m_A45; + m_A46 += m_A11 * f5_16; + RHS16 += f5_16 * RHS5; + const double f6 = 1.0 / m_A12; + const double f6_10 = -f6 * m_A23; + m_A24 += m_A13 * f6_10; + m_A25 += m_A14 * f6_10; + RHS10 += f6_10 * RHS6; + const double f6_13 = -f6 * m_A34; + m_A35 += m_A13 * f6_13; + m_A36 += m_A14 * f6_13; + RHS13 += f6_13 * RHS6; + const double f7 = 1.0 / m_A15; + const double f7_14 = -f7 * m_A37; + m_A39 += m_A16 * f7_14; + RHS14 += f7_14 * RHS7; + const double f7_17 = -f7 * m_A52; + m_A54 += m_A16 * f7_17; + RHS17 += f7_17 * RHS7; + const double f8 = 1.0 / m_A17; + const double f8_14 = -f8 * m_A38; + m_A39 += m_A18 * f8_14; + RHS14 += f8_14 * RHS8; + const double f10 = 1.0 / m_A24; + const double f10_13 = -f10 * m_A35; + m_A36 += m_A25 * f10_13; + RHS13 += f10_13 * RHS10; + const double f10_16 = -f10 * m_A46; + m_A48 += m_A25 * f10_16; + RHS16 += f10_16 * RHS10; + const double f11 = 1.0 / m_A27; + const double f11_12 = -f11 * m_A30; + m_A32 += m_A28 * f11_12; + RHS12 += f11_12 * RHS11; + const double f12 = 1.0 / m_A31; + const double f12_16 = -f12 * m_A47; + m_A49 += m_A32 * f12_16; + m_A50 += m_A33 * f12_16; + RHS16 += f12_16 * RHS12; + const double f12_17 = -f12 * m_A53; + m_A55 += m_A32 * f12_17; + m_A56 += m_A33 * f12_17; + RHS17 += f12_17 * RHS12; + const double f13 = 1.0 / m_A36; + const double f13_16 = -f13 * m_A48; + RHS16 += f13_16 * RHS13; + const double f14 = 1.0 / m_A39; + const double f14_17 = -f14 * m_A54; + RHS17 += f14_17 * RHS14; + const double f16 = 1.0 / m_A49; + const double f16_17 = -f16 * m_A55; + m_A56 += m_A50 * f16_17; + RHS17 += f16_17 * RHS16; + V[17] = RHS17 / m_A56; + double tmp16 = 0.0; + tmp16 += m_A50 * V[17]; + V[16] = (RHS16 - tmp16) / m_A49; + double tmp15 = 0.0; + tmp15 += m_A42 * V[17]; + V[15] = (RHS15 - tmp15) / m_A41; + double tmp14 = 0.0; + V[14] = (RHS14 - tmp14) / m_A39; + double tmp13 = 0.0; + V[13] = (RHS13 - tmp13) / m_A36; + double tmp12 = 0.0; + tmp12 += m_A32 * V[16]; + tmp12 += m_A33 * V[17]; + V[12] = (RHS12 - tmp12) / m_A31; + double tmp11 = 0.0; + tmp11 += m_A28 * V[16]; + V[11] = (RHS11 - tmp11) / m_A27; + double tmp10 = 0.0; + tmp10 += m_A25 * V[13]; + V[10] = (RHS10 - tmp10) / m_A24; + double tmp9 = 0.0; + tmp9 += m_A21 * V[15]; + V[9] = (RHS9 - tmp9) / m_A20; + double tmp8 = 0.0; + tmp8 += m_A18 * V[14]; + V[8] = (RHS8 - tmp8) / m_A17; + double tmp7 = 0.0; + tmp7 += m_A16 * V[14]; + V[7] = (RHS7 - tmp7) / m_A15; + double tmp6 = 0.0; + tmp6 += m_A13 * V[10]; + tmp6 += m_A14 * V[13]; + V[6] = (RHS6 - tmp6) / m_A12; + double tmp5 = 0.0; + tmp5 += m_A11 * V[10]; + V[5] = (RHS5 - tmp5) / m_A10; + double tmp4 = 0.0; + tmp4 += m_A9 * V[15]; + V[4] = (RHS4 - tmp4) / m_A8; + double tmp3 = 0.0; + tmp3 += m_A7 * V[17]; + V[3] = (RHS3 - tmp3) / m_A6; + double tmp2 = 0.0; + tmp2 += m_A5 * V[11]; + V[2] = (RHS2 - tmp2) / m_A4; + double tmp1 = 0.0; + tmp1 += m_A3 * V[16]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[16]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // sspeedr static void nl_gcr_95_double_double_4a8e2b707bbac8a6(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -62238,7 +63644,7 @@ static void nl_gcr_12_double_double_88a8ef5f6bd43d48(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// starcas,wotw,solarq,armora +// starcas,wotw,armora,solarq static void nl_gcr_22_double_double_1250f340dea396ae(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) { @@ -70535,8 +71941,8 @@ static void nl_gcr_20_double_double_c924fe5960b1479e(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } -// stuntcyc -static void nl_gcr_22_double_double_ca68d70bd8f2f62e(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) +// stuntcyc,brdrline +static void nl_gcr_7_double_double_59cb6bf7cb9d17dc(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) { @@ -70548,140 +71954,44 @@ static void nl_gcr_22_double_double_ca68d70bd8f2f62e(double * __restrict V, cons double m_A4(0.0); double m_A5(0.0); double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - double m_A12(0.0); - double m_A13(0.0); - double m_A14(0.0); - double m_A15(0.0); - double m_A16(0.0); - double m_A17(0.0); - double m_A18(0.0); - double m_A19(0.0); - double m_A20(0.0); - double m_A21(0.0); m_A0 += gt[0]; m_A0 += gt[1]; - m_A0 += gt[2]; - m_A0 += gt[3]; - m_A2 += go[0]; - m_A2 += go[1]; - m_A1 += go[2]; + m_A1 += go[0]; double RHS0 = Idr[0]; RHS0 += Idr[1]; - RHS0 += Idr[2]; - RHS0 += Idr[3]; - RHS0 -= go[3] * *cnV[3]; - m_A3 += gt[4]; - m_A3 += gt[5]; - m_A3 += gt[6]; - m_A3 += gt[7]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A3 += go[2]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 -= go[3] * *cnV[3]; + m_A6 += gt[4]; + m_A6 += gt[5]; + m_A6 += gt[6]; + m_A6 += gt[7]; m_A5 += go[4]; - m_A5 += go[5]; - m_A4 += go[6]; - double RHS1 = Idr[4]; - RHS1 += Idr[5]; - RHS1 += Idr[6]; - RHS1 += Idr[7]; - RHS1 -= go[7] * *cnV[7]; - m_A6 += gt[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A7 += go[8]; - double RHS2 = Idr[8]; - RHS2 += Idr[9]; - RHS2 += Idr[10]; - RHS2 -= go[9] * *cnV[9]; - RHS2 -= go[10] * *cnV[10]; - m_A10 += gt[11]; - m_A10 += gt[12]; - m_A10 += gt[13]; - m_A12 += go[11]; - m_A9 += go[12]; - m_A8 += go[13]; - double RHS3 = Idr[11]; - RHS3 += Idr[12]; - RHS3 += Idr[13]; - m_A16 += gt[14]; - m_A16 += gt[15]; - m_A16 += gt[16]; - m_A16 += gt[17]; - m_A16 += gt[18]; - m_A17 += go[14]; - m_A14 += go[15]; - m_A14 += go[16]; - m_A13 += go[17]; - m_A13 += go[18]; - double RHS4 = Idr[14]; - RHS4 += Idr[15]; - RHS4 += Idr[16]; - RHS4 += Idr[17]; - RHS4 += Idr[18]; - m_A21 += gt[19]; - m_A21 += gt[20]; - m_A21 += gt[21]; - m_A18 += go[19]; - m_A20 += go[20]; - m_A19 += go[21]; - double RHS5 = Idr[19]; - RHS5 += Idr[20]; - RHS5 += Idr[21]; + m_A4 += go[5]; + double RHS2 = Idr[4]; + RHS2 += Idr[5]; + RHS2 += Idr[6]; + RHS2 += Idr[7]; + RHS2 -= go[6] * *cnV[6]; + RHS2 -= go[7] * *cnV[7]; const double f0 = 1.0 / m_A0; - const double f0_3 = -f0 * m_A8; - m_A10 += m_A1 * f0_3; - m_A11 += m_A2 * f0_3; - RHS3 += f0_3 * RHS0; - const double f0_4 = -f0 * m_A13; - m_A15 += m_A1 * f0_4; - m_A16 += m_A2 * f0_4; - RHS4 += f0_4 * RHS0; - const double f1 = 1.0 / m_A3; - const double f1_3 = -f1 * m_A9; - m_A10 += m_A4 * f1_3; - m_A11 += m_A5 * f1_3; - RHS3 += f1_3 * RHS1; - const double f1_4 = -f1 * m_A14; - m_A15 += m_A4 * f1_4; - m_A16 += m_A5 * f1_4; - RHS4 += f1_4 * RHS1; - const double f2 = 1.0 / m_A6; - const double f2_5 = -f2 * m_A18; - m_A21 += m_A7 * f2_5; - RHS5 += f2_5 * RHS2; - const double f3 = 1.0 / m_A10; - const double f3_4 = -f3 * m_A15; - m_A16 += m_A11 * f3_4; - m_A17 += m_A12 * f3_4; - RHS4 += f3_4 * RHS3; - const double f3_5 = -f3 * m_A19; - m_A20 += m_A11 * f3_5; - m_A21 += m_A12 * f3_5; - RHS5 += f3_5 * RHS3; - const double f4 = 1.0 / m_A16; - const double f4_5 = -f4 * m_A20; - m_A21 += m_A17 * f4_5; - RHS5 += f4_5 * RHS4; - V[5] = RHS5 / m_A21; - double tmp4 = 0.0; - tmp4 += m_A17 * V[5]; - V[4] = (RHS4 - tmp4) / m_A16; - double tmp3 = 0.0; - tmp3 += m_A11 * V[4]; - tmp3 += m_A12 * V[5]; - V[3] = (RHS3 - tmp3) / m_A10; - double tmp2 = 0.0; - tmp2 += m_A7 * V[5]; - V[2] = (RHS2 - tmp2) / m_A6; + const double f0_2 = -f0 * m_A4; + m_A6 += m_A1 * f0_2; + RHS2 += f0_2 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + RHS2 += f1_2 * RHS1; + V[2] = RHS2 / m_A6; double tmp1 = 0.0; - tmp1 += m_A4 * V[3]; - tmp1 += m_A5 * V[4]; - V[1] = (RHS1 - tmp1) / m_A3; + tmp1 += m_A3 * V[2]; + V[1] = (RHS1 - tmp1) / m_A2; double tmp0 = 0.0; - tmp0 += m_A1 * V[3]; - tmp0 += m_A2 * V[4]; + tmp0 += m_A1 * V[2]; V[0] = (RHS0 - tmp0) / m_A0; } @@ -71400,105 +72710,6 @@ static void nl_gcr_100_double_double_e02a162cb515a958(double * __restrict V, con V[0] = (RHS0 - tmp0) / m_A0; } -// sundance,warrior -static void nl_gcr_12_double_double_ad6dba01ff2425c3(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) - -{ - - plib::unused_var(cnV); - double m_A0(0.0); - double m_A1(0.0); - double m_A2(0.0); - double m_A3(0.0); - double m_A4(0.0); - double m_A5(0.0); - double m_A6(0.0); - double m_A7(0.0); - double m_A8(0.0); - double m_A9(0.0); - double m_A10(0.0); - double m_A11(0.0); - m_A0 += gt[0]; - m_A0 += gt[1]; - m_A1 += go[0]; - double RHS0 = Idr[0]; - RHS0 += Idr[1]; - RHS0 -= go[1] * *cnV[1]; - m_A2 += gt[2]; - m_A2 += gt[3]; - m_A2 += gt[4]; - m_A2 += gt[5]; - m_A2 += gt[6]; - m_A4 += go[2]; - m_A3 += go[3]; - m_A3 += go[4]; - double RHS1 = Idr[2]; - RHS1 += Idr[3]; - RHS1 += Idr[4]; - RHS1 += Idr[5]; - RHS1 += Idr[6]; - RHS1 -= go[5] * *cnV[5]; - RHS1 -= go[6] * *cnV[6]; - m_A6 += gt[7]; - m_A6 += gt[8]; - m_A6 += gt[9]; - m_A6 += gt[10]; - m_A6 += gt[11]; - m_A7 += go[7]; - m_A7 += go[8]; - m_A5 += go[9]; - m_A5 += go[10]; - double RHS2 = Idr[7]; - RHS2 += Idr[8]; - RHS2 += Idr[9]; - RHS2 += Idr[10]; - RHS2 += Idr[11]; - RHS2 -= go[11] * *cnV[11]; - m_A11 += gt[12]; - m_A11 += gt[13]; - m_A11 += gt[14]; - m_A11 += gt[15]; - m_A11 += gt[16]; - m_A10 += go[12]; - m_A10 += go[13]; - m_A9 += go[14]; - m_A8 += go[15]; - double RHS3 = Idr[12]; - RHS3 += Idr[13]; - RHS3 += Idr[14]; - RHS3 += Idr[15]; - RHS3 += Idr[16]; - RHS3 -= go[16] * *cnV[16]; - const double f0 = 1.0 / m_A0; - const double f0_3 = -f0 * m_A8; - m_A11 += m_A1 * f0_3; - RHS3 += f0_3 * RHS0; - const double f1 = 1.0 / m_A2; - const double f1_2 = -f1 * m_A5; - m_A6 += m_A3 * f1_2; - m_A7 += m_A4 * f1_2; - RHS2 += f1_2 * RHS1; - const double f1_3 = -f1 * m_A9; - m_A10 += m_A3 * f1_3; - m_A11 += m_A4 * f1_3; - RHS3 += f1_3 * RHS1; - const double f2 = 1.0 / m_A6; - const double f2_3 = -f2 * m_A10; - m_A11 += m_A7 * f2_3; - RHS3 += f2_3 * RHS2; - V[3] = RHS3 / m_A11; - double tmp2 = 0.0; - tmp2 += m_A7 * V[3]; - V[2] = (RHS2 - tmp2) / m_A6; - double tmp1 = 0.0; - tmp1 += m_A3 * V[2]; - tmp1 += m_A4 * V[3]; - V[1] = (RHS1 - tmp1) / m_A2; - double tmp0 = 0.0; - tmp0 += m_A1 * V[3]; - V[0] = (RHS0 - tmp0) / m_A0; -} - // sundance static void nl_gcr_70_double_double_8446e63d7842f6a6(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -77174,6 +78385,102 @@ static void nl_gcr_10_double_double_8003d4625273fa4d(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } +// warrior,ripoff,sundance +static void nl_gcr_12_double_double_295cf2e2f3d489bf(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A4 += go[2]; + m_A3 += go[3]; + m_A3 += go[4]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 -= go[5] * *cnV[5]; + m_A6 += gt[6]; + m_A6 += gt[7]; + m_A6 += gt[8]; + m_A6 += gt[9]; + m_A6 += gt[10]; + m_A7 += go[6]; + m_A7 += go[7]; + m_A5 += go[8]; + m_A5 += go[9]; + double RHS2 = Idr[6]; + RHS2 += Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 -= go[10] * *cnV[10]; + m_A11 += gt[11]; + m_A11 += gt[12]; + m_A11 += gt[13]; + m_A11 += gt[14]; + m_A11 += gt[15]; + m_A10 += go[11]; + m_A10 += go[12]; + m_A9 += go[13]; + m_A8 += go[14]; + double RHS3 = Idr[11]; + RHS3 += Idr[12]; + RHS3 += Idr[13]; + RHS3 += Idr[14]; + RHS3 += Idr[15]; + RHS3 -= go[15] * *cnV[15]; + const double f0 = 1.0 / m_A0; + const double f0_3 = -f0 * m_A8; + m_A11 += m_A1 * f0_3; + RHS3 += f0_3 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + m_A7 += m_A4 * f1_2; + RHS2 += f1_2 * RHS1; + const double f1_3 = -f1 * m_A9; + m_A10 += m_A3 * f1_3; + m_A11 += m_A4 * f1_3; + RHS3 += f1_3 * RHS1; + const double f2 = 1.0 / m_A6; + const double f2_3 = -f2 * m_A10; + m_A11 += m_A7 * f2_3; + RHS3 += f2_3 * RHS2; + V[3] = RHS3 / m_A11; + double tmp2 = 0.0; + tmp2 += m_A7 * V[3]; + V[2] = (RHS2 - tmp2) / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + tmp1 += m_A4 * V[3]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[3]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // warrior static void nl_gcr_12_double_double_42a31ce5c187b308(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -77249,6 +78556,105 @@ static void nl_gcr_12_double_double_42a31ce5c187b308(double * __restrict V, cons V[0] = (RHS0 - tmp0) / m_A0; } +// warrior,sundance +static void nl_gcr_12_double_double_ad6dba01ff2425c3(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) + +{ + + plib::unused_var(cnV); + double m_A0(0.0); + double m_A1(0.0); + double m_A2(0.0); + double m_A3(0.0); + double m_A4(0.0); + double m_A5(0.0); + double m_A6(0.0); + double m_A7(0.0); + double m_A8(0.0); + double m_A9(0.0); + double m_A10(0.0); + double m_A11(0.0); + m_A0 += gt[0]; + m_A0 += gt[1]; + m_A1 += go[0]; + double RHS0 = Idr[0]; + RHS0 += Idr[1]; + RHS0 -= go[1] * *cnV[1]; + m_A2 += gt[2]; + m_A2 += gt[3]; + m_A2 += gt[4]; + m_A2 += gt[5]; + m_A2 += gt[6]; + m_A4 += go[2]; + m_A3 += go[3]; + m_A3 += go[4]; + double RHS1 = Idr[2]; + RHS1 += Idr[3]; + RHS1 += Idr[4]; + RHS1 += Idr[5]; + RHS1 += Idr[6]; + RHS1 -= go[5] * *cnV[5]; + RHS1 -= go[6] * *cnV[6]; + m_A6 += gt[7]; + m_A6 += gt[8]; + m_A6 += gt[9]; + m_A6 += gt[10]; + m_A6 += gt[11]; + m_A7 += go[7]; + m_A7 += go[8]; + m_A5 += go[9]; + m_A5 += go[10]; + double RHS2 = Idr[7]; + RHS2 += Idr[8]; + RHS2 += Idr[9]; + RHS2 += Idr[10]; + RHS2 += Idr[11]; + RHS2 -= go[11] * *cnV[11]; + m_A11 += gt[12]; + m_A11 += gt[13]; + m_A11 += gt[14]; + m_A11 += gt[15]; + m_A11 += gt[16]; + m_A10 += go[12]; + m_A10 += go[13]; + m_A9 += go[14]; + m_A8 += go[15]; + double RHS3 = Idr[12]; + RHS3 += Idr[13]; + RHS3 += Idr[14]; + RHS3 += Idr[15]; + RHS3 += Idr[16]; + RHS3 -= go[16] * *cnV[16]; + const double f0 = 1.0 / m_A0; + const double f0_3 = -f0 * m_A8; + m_A11 += m_A1 * f0_3; + RHS3 += f0_3 * RHS0; + const double f1 = 1.0 / m_A2; + const double f1_2 = -f1 * m_A5; + m_A6 += m_A3 * f1_2; + m_A7 += m_A4 * f1_2; + RHS2 += f1_2 * RHS1; + const double f1_3 = -f1 * m_A9; + m_A10 += m_A3 * f1_3; + m_A11 += m_A4 * f1_3; + RHS3 += f1_3 * RHS1; + const double f2 = 1.0 / m_A6; + const double f2_3 = -f2 * m_A10; + m_A11 += m_A7 * f2_3; + RHS3 += f2_3 * RHS2; + V[3] = RHS3 / m_A11; + double tmp2 = 0.0; + tmp2 += m_A7 * V[3]; + V[2] = (RHS2 - tmp2) / m_A6; + double tmp1 = 0.0; + tmp1 += m_A3 * V[2]; + tmp1 += m_A4 * V[3]; + V[1] = (RHS1 - tmp1) / m_A2; + double tmp0 = 0.0; + tmp0 += m_A1 * V[3]; + V[0] = (RHS0 - tmp0) / m_A0; +} + // warrior static void nl_gcr_27_double_double_da598f43329e823(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV) @@ -81833,16 +83239,8 @@ const plib::static_library::symbol nl_static_solver_syms[] = { // 1942 {"nl_gcr_90_double_double_ce766957cb26ff3e", reinterpret_cast<void *>(&nl_gcr_90_double_double_ce766957cb26ff3e)}, // NOLINT -// 280zzzap,sspeedr - {"nl_gcr_113_double_double_ab9144d965a37e4", reinterpret_cast<void *>(&nl_gcr_113_double_double_ab9144d965a37e4)}, // NOLINT -// 280zzzap,sspeedr - {"nl_gcr_122_double_double_42c57d523cac30d0", reinterpret_cast<void *>(&nl_gcr_122_double_double_42c57d523cac30d0)}, // NOLINT -// 280zzzap,sspeedr - {"nl_gcr_123_double_double_864a61c57bac9c38", reinterpret_cast<void *>(&nl_gcr_123_double_double_864a61c57bac9c38)}, // NOLINT // 280zzzap {"nl_gcr_149_double_double_fc9971724787b82b", reinterpret_cast<void *>(&nl_gcr_149_double_double_fc9971724787b82b)}, // NOLINT -// 280zzzap,sspeedr - {"nl_gcr_57_double_double_bb501e6a23177009", reinterpret_cast<void *>(&nl_gcr_57_double_double_bb501e6a23177009)}, // NOLINT // 280zzzap {"nl_gcr_95_double_double_24643c159711f292", reinterpret_cast<void *>(&nl_gcr_95_double_double_24643c159711f292)}, // NOLINT // armora @@ -81855,8 +83253,6 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_58_double_double_64e460d8f716cd89", reinterpret_cast<void *>(&nl_gcr_58_double_double_64e460d8f716cd89)}, // NOLINT // armora {"nl_gcr_67_double_double_ee2cacaa15d32491", reinterpret_cast<void *>(&nl_gcr_67_double_double_ee2cacaa15d32491)}, // NOLINT -// astrob,rebound - {"nl_gcr_13_double_double_a41a44bd5c424f88", reinterpret_cast<void *>(&nl_gcr_13_double_double_a41a44bd5c424f88)}, // NOLINT // astrob {"nl_gcr_154_double_double_13833bf8c127deaa", reinterpret_cast<void *>(&nl_gcr_154_double_double_13833bf8c127deaa)}, // NOLINT // astrob @@ -81925,8 +83321,6 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_75_double_double_75400df5d559a266", reinterpret_cast<void *>(&nl_gcr_75_double_double_75400df5d559a266)}, // NOLINT // brdrline {"nl_gcr_77_double_double_437326911721091", reinterpret_cast<void *>(&nl_gcr_77_double_double_437326911721091)}, // NOLINT -// brdrline,stuntcyc - {"nl_gcr_7_double_double_59cb6bf7cb9d17dc", reinterpret_cast<void *>(&nl_gcr_7_double_double_59cb6bf7cb9d17dc)}, // NOLINT // brdrline {"nl_gcr_83_double_double_f99b1245e708ec85", reinterpret_cast<void *>(&nl_gcr_83_double_double_f99b1245e708ec85)}, // NOLINT // brdrline @@ -81965,6 +83359,18 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_16_double_double_8c0f7f2284333de5", reinterpret_cast<void *>(&nl_gcr_16_double_double_8c0f7f2284333de5)}, // NOLINT // destroyr {"nl_gcr_399_double_double_4334c95878d1be92", reinterpret_cast<void *>(&nl_gcr_399_double_double_4334c95878d1be92)}, // NOLINT +// dribling + {"nl_gcr_21_double_double_c9b5f1625a51d98f", reinterpret_cast<void *>(&nl_gcr_21_double_double_c9b5f1625a51d98f)}, // NOLINT +// dribling + {"nl_gcr_28_double_double_99f81817ea8bea2d", reinterpret_cast<void *>(&nl_gcr_28_double_double_99f81817ea8bea2d)}, // NOLINT +// dribling + {"nl_gcr_29_double_double_1e732268bc2d78b2", reinterpret_cast<void *>(&nl_gcr_29_double_double_1e732268bc2d78b2)}, // NOLINT +// dribling + {"nl_gcr_54_double_double_a2823a76b83c45a0", reinterpret_cast<void *>(&nl_gcr_54_double_double_a2823a76b83c45a0)}, // NOLINT +// dribling + {"nl_gcr_7_double_double_a1ecff4d37b54b76", reinterpret_cast<void *>(&nl_gcr_7_double_double_a1ecff4d37b54b76)}, // NOLINT +// dribling + {"nl_gcr_95_double_double_a0159c41cfc0b644", reinterpret_cast<void *>(&nl_gcr_95_double_double_a0159c41cfc0b644)}, // NOLINT // elim,zektor {"nl_gcr_10_double_double_11c2ae166b240b6e", reinterpret_cast<void *>(&nl_gcr_10_double_double_11c2ae166b240b6e)}, // NOLINT // elim,zektor @@ -81989,8 +83395,6 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_36_double_double_e76692c10e79997e", reinterpret_cast<void *>(&nl_gcr_36_double_double_e76692c10e79997e)}, // NOLINT // elim,zektor {"nl_gcr_45_double_double_28b736fe552777a9", reinterpret_cast<void *>(&nl_gcr_45_double_double_28b736fe552777a9)}, // NOLINT -// elim,zektor - {"nl_gcr_7_double_double_d190a0e3b8e1f4a7", reinterpret_cast<void *>(&nl_gcr_7_double_double_d190a0e3b8e1f4a7)}, // NOLINT // fireone {"nl_gcr_128_double_double_7aee4423e3fdbfda", reinterpret_cast<void *>(&nl_gcr_128_double_double_7aee4423e3fdbfda)}, // NOLINT // fireone @@ -82009,8 +83413,6 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_73_double_double_643133e86b2b1628", reinterpret_cast<void *>(&nl_gcr_73_double_double_643133e86b2b1628)}, // NOLINT // fireone {"nl_gcr_79_double_double_c1d22fe6e895255d", reinterpret_cast<void *>(&nl_gcr_79_double_double_c1d22fe6e895255d)}, // NOLINT -// fireone,astrob,rebound,speedfrk,cheekyms - {"nl_gcr_7_double_double_7c86a9bc1c6aef4c", reinterpret_cast<void *>(&nl_gcr_7_double_double_7c86a9bc1c6aef4c)}, // NOLINT // fireone {"nl_gcr_7_double_double_e7fb484f621b3ab9", reinterpret_cast<void *>(&nl_gcr_7_double_double_e7fb484f621b3ab9)}, // NOLINT // fireone @@ -82043,8 +83445,14 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_10_double_double_934712b55bb3b2b2", reinterpret_cast<void *>(&nl_gcr_10_double_double_934712b55bb3b2b2)}, // NOLINT // gamemachine {"nl_gcr_7_double_double_782d79b5cbe953b1", reinterpret_cast<void *>(&nl_gcr_7_double_double_782d79b5cbe953b1)}, // NOLINT +// gi6809 + {"nl_gcr_13_double_double_9eda6de0d275a3e5", reinterpret_cast<void *>(&nl_gcr_13_double_double_9eda6de0d275a3e5)}, // NOLINT +// gi6809 + {"nl_gcr_7_double_double_8a409a18e77784cb", reinterpret_cast<void *>(&nl_gcr_7_double_double_8a409a18e77784cb)}, // NOLINT // gtrak10 - {"nl_gcr_43_double_double_4c46fdf7c0037727", reinterpret_cast<void *>(&nl_gcr_43_double_double_4c46fdf7c0037727)}, // NOLINT + {"nl_gcr_22_double_double_1f38df4919cdddae", reinterpret_cast<void *>(&nl_gcr_22_double_double_1f38df4919cdddae)}, // NOLINT +// gtrak10,elim,zektor + {"nl_gcr_7_double_double_d190a0e3b8e1f4a7", reinterpret_cast<void *>(&nl_gcr_7_double_double_d190a0e3b8e1f4a7)}, // NOLINT // gunfight {"nl_gcr_112_double_double_743595e64cee0a5e", reinterpret_cast<void *>(&nl_gcr_112_double_double_743595e64cee0a5e)}, // NOLINT // gunfight @@ -82081,6 +83489,8 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_7_double_double_e51b463cd890ef6d", reinterpret_cast<void *>(&nl_gcr_7_double_double_e51b463cd890ef6d)}, // NOLINT // popeye {"nl_gcr_50_double_double_c6f25bb06e161d1c", reinterpret_cast<void *>(&nl_gcr_50_double_double_c6f25bb06e161d1c)}, // NOLINT +// rebound,astrob + {"nl_gcr_13_double_double_a41a44bd5c424f88", reinterpret_cast<void *>(&nl_gcr_13_double_double_a41a44bd5c424f88)}, // NOLINT // rebound {"nl_gcr_28_double_double_8bec817b324dcc3", reinterpret_cast<void *>(&nl_gcr_28_double_double_8bec817b324dcc3)}, // NOLINT // rebound @@ -82089,8 +83499,6 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_10_double_double_43188bf576854ae0", reinterpret_cast<void *>(&nl_gcr_10_double_double_43188bf576854ae0)}, // NOLINT // ripoff {"nl_gcr_11_double_double_aa07266ef5d420d1", reinterpret_cast<void *>(&nl_gcr_11_double_double_aa07266ef5d420d1)}, // NOLINT -// ripoff,sundance,warrior - {"nl_gcr_12_double_double_295cf2e2f3d489bf", reinterpret_cast<void *>(&nl_gcr_12_double_double_295cf2e2f3d489bf)}, // NOLINT // ripoff {"nl_gcr_16_double_double_698d5dd47fb16d5", reinterpret_cast<void *>(&nl_gcr_16_double_double_698d5dd47fb16d5)}, // NOLINT // ripoff @@ -82157,21 +83565,31 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_91_double_double_b7b209d222c0a9a6", reinterpret_cast<void *>(&nl_gcr_91_double_double_b7b209d222c0a9a6)}, // NOLINT // speedfrk {"nl_gcr_37_double_double_e4f2ffbf201a3d0c", reinterpret_cast<void *>(&nl_gcr_37_double_double_e4f2ffbf201a3d0c)}, // NOLINT +// speedfrk,cheekyms,rebound,astrob,fireone + {"nl_gcr_7_double_double_7c86a9bc1c6aef4c", reinterpret_cast<void *>(&nl_gcr_7_double_double_7c86a9bc1c6aef4c)}, // NOLINT // speedfrk {"nl_gcr_7_double_double_e07b5b086812756c", reinterpret_cast<void *>(&nl_gcr_7_double_double_e07b5b086812756c)}, // NOLINT // sspeedr {"nl_gcr_10_double_double_ac1e401ddf971e15", reinterpret_cast<void *>(&nl_gcr_10_double_double_ac1e401ddf971e15)}, // NOLINT +// sspeedr,280zzzap + {"nl_gcr_113_double_double_ab9144d965a37e4", reinterpret_cast<void *>(&nl_gcr_113_double_double_ab9144d965a37e4)}, // NOLINT +// sspeedr,280zzzap + {"nl_gcr_122_double_double_42c57d523cac30d0", reinterpret_cast<void *>(&nl_gcr_122_double_double_42c57d523cac30d0)}, // NOLINT +// sspeedr,280zzzap + {"nl_gcr_123_double_double_864a61c57bac9c38", reinterpret_cast<void *>(&nl_gcr_123_double_double_864a61c57bac9c38)}, // NOLINT // sspeedr {"nl_gcr_13_double_double_3e833834e5ce5aee", reinterpret_cast<void *>(&nl_gcr_13_double_double_3e833834e5ce5aee)}, // NOLINT // sspeedr {"nl_gcr_176_double_double_2294220d3c91e762", reinterpret_cast<void *>(&nl_gcr_176_double_double_2294220d3c91e762)}, // NOLINT +// sspeedr,280zzzap + {"nl_gcr_57_double_double_bb501e6a23177009", reinterpret_cast<void *>(&nl_gcr_57_double_double_bb501e6a23177009)}, // NOLINT // sspeedr {"nl_gcr_95_double_double_4a8e2b707bbac8a6", reinterpret_cast<void *>(&nl_gcr_95_double_double_4a8e2b707bbac8a6)}, // NOLINT // starcas,wotw {"nl_gcr_109_double_double_5d550fc7441617a2", reinterpret_cast<void *>(&nl_gcr_109_double_double_5d550fc7441617a2)}, // NOLINT // starcas,wotw {"nl_gcr_12_double_double_88a8ef5f6bd43d48", reinterpret_cast<void *>(&nl_gcr_12_double_double_88a8ef5f6bd43d48)}, // NOLINT -// starcas,wotw,solarq,armora +// starcas,wotw,armora,solarq {"nl_gcr_22_double_double_1250f340dea396ae", reinterpret_cast<void *>(&nl_gcr_22_double_double_1250f340dea396ae)}, // NOLINT // starcas,wotw,boxingb {"nl_gcr_23_double_double_ea2b6e3a05e6ef0b", reinterpret_cast<void *>(&nl_gcr_23_double_double_ea2b6e3a05e6ef0b)}, // NOLINT @@ -82215,12 +83633,10 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_10_double_double_85652d3e3ada285a", reinterpret_cast<void *>(&nl_gcr_10_double_double_85652d3e3ada285a)}, // NOLINT // stuntcyc {"nl_gcr_20_double_double_c924fe5960b1479e", reinterpret_cast<void *>(&nl_gcr_20_double_double_c924fe5960b1479e)}, // NOLINT -// stuntcyc - {"nl_gcr_22_double_double_ca68d70bd8f2f62e", reinterpret_cast<void *>(&nl_gcr_22_double_double_ca68d70bd8f2f62e)}, // NOLINT +// stuntcyc,brdrline + {"nl_gcr_7_double_double_59cb6bf7cb9d17dc", reinterpret_cast<void *>(&nl_gcr_7_double_double_59cb6bf7cb9d17dc)}, // NOLINT // sundance {"nl_gcr_100_double_double_e02a162cb515a958", reinterpret_cast<void *>(&nl_gcr_100_double_double_e02a162cb515a958)}, // NOLINT -// sundance,warrior - {"nl_gcr_12_double_double_ad6dba01ff2425c3", reinterpret_cast<void *>(&nl_gcr_12_double_double_ad6dba01ff2425c3)}, // NOLINT // sundance {"nl_gcr_70_double_double_8446e63d7842f6a6", reinterpret_cast<void *>(&nl_gcr_70_double_double_8446e63d7842f6a6)}, // NOLINT // sundance @@ -82253,8 +83669,12 @@ const plib::static_library::symbol nl_static_solver_syms[] = { {"nl_gcr_7_double_double_74349e9889a2630b", reinterpret_cast<void *>(&nl_gcr_7_double_double_74349e9889a2630b)}, // NOLINT // warrior {"nl_gcr_10_double_double_8003d4625273fa4d", reinterpret_cast<void *>(&nl_gcr_10_double_double_8003d4625273fa4d)}, // NOLINT +// warrior,ripoff,sundance + {"nl_gcr_12_double_double_295cf2e2f3d489bf", reinterpret_cast<void *>(&nl_gcr_12_double_double_295cf2e2f3d489bf)}, // NOLINT // warrior {"nl_gcr_12_double_double_42a31ce5c187b308", reinterpret_cast<void *>(&nl_gcr_12_double_double_42a31ce5c187b308)}, // NOLINT +// warrior,sundance + {"nl_gcr_12_double_double_ad6dba01ff2425c3", reinterpret_cast<void *>(&nl_gcr_12_double_double_ad6dba01ff2425c3)}, // NOLINT // warrior {"nl_gcr_27_double_double_da598f43329e823", reinterpret_cast<void *>(&nl_gcr_27_double_double_da598f43329e823)}, // NOLINT // warrior diff --git a/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp b/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp index 4e668766c04..2a1d844d512 100644 --- a/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp +++ b/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp @@ -1046,7 +1046,7 @@ static NETLIST_START(TTL_7474_DIP) //- Package: DIP //- NamingConvention: Naming conventions follow National Semiconductor datasheet //- FunctionTable: -//- https://ia800608.us.archive.org/5/items/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf +//- https://archive.org/download/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf //- //- +---+---++---+----+ //- | D | G || Q | QQ | @@ -1088,7 +1088,7 @@ static NETLIST_START(TTL_7475_DIP) //- Package: DIP //- NamingConvention: Naming conventions follow National Semiconductor datasheet //- FunctionTable: -//- https://ia800608.us.archive.org/5/items/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf +//- https://archive.org/download/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf //- //- +---+---++---+----+ //- | D | G || Q | QQ | @@ -2831,7 +2831,7 @@ static NETLIST_START(SN74LS629_DIP) //- Package: DIP //- NamingConvention: Naming conventions follow National Semiconductor datasheet //- FunctionTable: -//- https://ia800608.us.archive.org/5/items/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf +//- https://archive.org/download/bitsavers_nationaldaTTLDatabook_40452765/1976_National_TTL_Databook.pdf //- static NETLIST_START(TTL_9310_DIP) { diff --git a/src/lib/netlist/nl_create_mame_solvers.sh b/src/lib/netlist/nl_create_mame_solvers.sh index 25826efaed3..4786e11eaed 100644..100755 --- a/src/lib/netlist/nl_create_mame_solvers.sh +++ b/src/lib/netlist/nl_create_mame_solvers.sh @@ -16,7 +16,7 @@ mkdir ${OUTDIR} #--dir src/lib/netlist/generated/static --static-include -if ${NLTOOL} --cmd static --output=${GENERATED}.tmp --include=src/mame/audio ${FILES} ; then +if ${NLTOOL} --cmd static --output=${GENERATED}.tmp --include=src/mame/shared ${FILES} ; then mv -f ${GENERATED}.tmp ${GENERATED} echo Created ${GENERATED} file else diff --git a/src/lib/netlist/nl_dice_compat.h b/src/lib/netlist/nl_dice_compat.h index 3088829b5f9..aff1ac4da6f 100644 --- a/src/lib/netlist/nl_dice_compat.h +++ b/src/lib/netlist/nl_dice_compat.h @@ -16,7 +16,7 @@ sed -e 's/#define \(.*\)"\(.*\)"[ \t]*,[ \t]*\(.*\)/NET_ALIAS(\1,\2.\3)/' src/ma | sed -e 's/) RES(/)\n RES(/g' \ | sed -e 's/) CAP(/)\n CAP(/g' \ | sed -e 's/) NET_C(/)\n NET_C(/g' \ -| sed -e 's/NL_EMPTY//' \ +| sed -e 's/NL_EMPTY//' * */ diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp index 168cb172473..b358f3ad6ba 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -8,7 +8,7 @@ #include <cfloat> #include <iostream> -#if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GLIBC__) #define HAS_FEENABLE_EXCEPT (1) #else #define HAS_FEENABLE_EXCEPT (0) diff --git a/src/lib/netlist/plib/ppreprocessor.cpp b/src/lib/netlist/plib/ppreprocessor.cpp index fd545bc7879..0c3858862f6 100644 --- a/src/lib/netlist/plib/ppreprocessor.cpp +++ b/src/lib/netlist/plib/ppreprocessor.cpp @@ -146,7 +146,7 @@ namespace plib { sexpr.next(); \ const auto v2 = prepro_expr(sexpr, (p_prio)); \ val = (val p_op v2); \ - } \ + } // Operator precedence see https://en.cppreference.com/w/cpp/language/operator_precedence diff --git a/src/lib/netlist/plib/ptests.h b/src/lib/netlist/plib/ptests.h index cc05b120b96..4e65de7f978 100644 --- a/src/lib/netlist/plib/ptests.h +++ b/src/lib/netlist/plib/ptests.h @@ -47,7 +47,7 @@ #define PINT_REGISTER(name, desc) \ extern const plib::testing::reg_entry<PINT_TESTNAME(name, desc)> PINT_TESTNAME(name, desc ## _reg); \ - const plib::testing::reg_entry<PINT_TESTNAME(name, desc)> PINT_TESTNAME(name, desc ## _reg)(#name, #desc, PINT_LOCATION()); \ + const plib::testing::reg_entry<PINT_TESTNAME(name, desc)> PINT_TESTNAME(name, desc ## _reg)(#name, #desc, PINT_LOCATION()); #define PINT_TEST_F(name, desc, base) \ class PINT_TESTNAME(name, desc) : public base \ @@ -296,7 +296,7 @@ namespace plib::testing static const char * opstr() { return #op ; } \ template <typename T1, typename T2> \ bool operator()(const T1 &v1, const T2 &v2) { return v1 op v2; } \ - }; \ + }; DEF_COMP(eq, ==) DEF_COMP(ne, !=) diff --git a/src/lib/netlist/tests/test_penum.cpp b/src/lib/netlist/tests/test_penum.cpp index 8e90c8537e1..6347a41d027 100644 --- a/src/lib/netlist/tests/test_penum.cpp +++ b/src/lib/netlist/tests/test_penum.cpp @@ -91,7 +91,7 @@ namespace plib return; } } - constexpr operator const char * () const noexcept { return staticf::m_str[static_cast<std::size_t>(m_v)]; } \ + constexpr operator const char * () const noexcept { return staticf::m_str[static_cast<std::size_t>(m_v)]; } constexpr operator E () const noexcept { return m_v; } protected: E m_v; diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp index 8fe3b19eca8..2859034c166 100644 --- a/src/lib/netlist/tools/nl_convert.cpp +++ b/src/lib/netlist/tools/nl_convert.cpp @@ -340,7 +340,7 @@ void nl_convert_spice_t::convert_block(const str_list &contents) { process_line(line); } - catch (const plib::pexception &e) + catch ([[maybe_unused]] const plib::pexception &e) { fprintf(stderr, "Error on line: <%d>\n", linenumber); throw; diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp index 40ce6ebe689..7b5e8d00d87 100644 --- a/src/lib/util/aviio.cpp +++ b/src/lib/util/aviio.cpp @@ -48,7 +48,7 @@ static constexpr std::uint64_t FOUR_GB = std::uint64_t(1) << 32; * @brief A constant that defines maximum sound channels. */ -static constexpr unsigned MAX_SOUND_CHANNELS = 2; +static constexpr unsigned MAX_SOUND_CHANNELS = 16; /** * @def SOUND_BUFFER_MSEC diff --git a/src/lib/util/bitstream.h b/src/lib/util/bitstream.h index 4f3817afe6f..eb8b2005329 100644 --- a/src/lib/util/bitstream.h +++ b/src/lib/util/bitstream.h @@ -40,10 +40,11 @@ public: private: // internal state uint32_t m_buffer; // current bit accumulator - int m_bits; // number of bits in the accumulator + int m_bits; // number of bits in the accumulator const uint8_t * m_read; // read pointer uint32_t m_doffset; // byte offset within the data uint32_t m_dlength; // length of the data + int m_dbitoffs; // bit offset within current read pointer }; @@ -64,7 +65,7 @@ public: private: // internal state uint32_t m_buffer; // current bit accumulator - int m_bits; // number of bits in the accumulator + int m_bits; // number of bits in the accumulator uint8_t * m_write; // write pointer uint32_t m_doffset; // byte offset within the data uint32_t m_dlength; // length of the data @@ -85,7 +86,8 @@ inline bitstream_in::bitstream_in(const void *src, uint32_t srclength) m_bits(0), m_read(reinterpret_cast<const uint8_t *>(src)), m_doffset(0), - m_dlength(srclength) + m_dlength(srclength), + m_dbitoffs(0) { } @@ -103,12 +105,31 @@ inline uint32_t bitstream_in::peek(int numbits) // fetch data if we need more if (numbits > m_bits) { - while (m_bits <= 24) + while (m_bits < 32) { + uint32_t newbits = 0; + if (m_doffset < m_dlength) - m_buffer |= m_read[m_doffset] << (24 - m_bits); - m_doffset++; - m_bits += 8; + { + // adjust current data to discard any previously read partial bits + newbits = (m_read[m_doffset] << m_dbitoffs) & 0xff; + } + + if (m_bits + 8 > 32) + { + // take only what can be used to fill out the rest of the buffer + m_dbitoffs = 32 - m_bits; + newbits >>= 8 - m_dbitoffs; + m_buffer |= newbits; + m_bits += m_dbitoffs; + } + else + { + m_buffer |= newbits << (24 - m_bits); + m_bits += 8 - m_dbitoffs; + m_dbitoffs = 0; + m_doffset++; + } } } @@ -154,6 +175,10 @@ inline uint32_t bitstream_in::read_offset() const result--; bits -= 8; } + + if (m_dbitoffs > bits) + result++; + return result; } @@ -169,7 +194,11 @@ inline uint32_t bitstream_in::flush() m_doffset--; m_bits -= 8; } - m_bits = m_buffer = 0; + + if (m_dbitoffs > m_bits) + m_doffset++; + + m_bits = m_buffer = m_dbitoffs = 0; return m_doffset; } @@ -196,8 +225,11 @@ inline bitstream_out::bitstream_out(void *dest, uint32_t destlength) inline void bitstream_out::write(uint32_t newbits, int numbits) { + newbits <<= 32 - numbits; + // flush the buffer if we're going to overflow it - if (m_bits + numbits > 32) + while (m_bits + numbits >= 32 && numbits > 0) + { while (m_bits >= 8) { if (m_doffset < m_dlength) @@ -207,11 +239,19 @@ inline void bitstream_out::write(uint32_t newbits, int numbits) m_bits -= 8; } - // shift the bits to the top - if (numbits == 0) - newbits = 0; - else - newbits <<= 32 - numbits; + // offload more bits if it'll still overflow the buffer + if (m_bits + numbits >= 32) + { + const int rem = std::min(32 - m_bits, numbits); + m_buffer |= newbits >> m_bits; + m_bits += rem; + newbits <<= rem; + numbits -= rem; + } + } + + if (numbits <= 0) + return; // now shift it down to account for the number of bits we already have and OR them in m_buffer |= newbits >> m_bits; diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp index 36a51104d3c..ab227dce1eb 100644 --- a/src/lib/util/cdrom.cpp +++ b/src/lib/util/cdrom.cpp @@ -21,10 +21,12 @@ #include "corestr.h" #include "multibyte.h" #include "osdfile.h" +#include "path.h" #include "strformat.h" #include <cassert> #include <cstdlib> +#include <tuple> /*************************************************************************** @@ -34,7 +36,6 @@ /** @brief The verbose. */ #define VERBOSE (0) #define EXTRA_VERBOSE (0) -#if VERBOSE /** * @def LOG(x) do @@ -44,31 +45,7 @@ * @param x The void to process. */ -#define LOG(x) do { if (VERBOSE) logerror x; } while (0) - -/** - * @fn void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); - * - * @brief Logerrors the given text. - * - * @param text The text. - * - * @return A CLIB_DECL. - */ - -void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); -#else - -/** - * @def LOG(x); - * - * @brief A macro that defines log. - * - * @param x The void to process. - */ - -#define LOG(x) -#endif +#define LOG(x) do { if (VERBOSE) { osd_printf_info x; } } while (0) @@ -159,7 +136,7 @@ cdrom_file::cdrom_file(std::string_view inputfile) std::error_condition err = parse_toc(inputfile, cdtoc, cdtrack_info); if (err) { - fprintf(stderr, "Error reading input file: %s\n", err.message().c_str()); + osd_printf_error("Error reading input file: %s\n", err.message()); throw nullptr; } @@ -175,13 +152,13 @@ cdrom_file::cdrom_file(std::string_view inputfile) std::error_condition const filerr = osd_file::open(cdtrack_info.track[i].fname, OPEN_FLAG_READ, file, length); if (filerr) { - fprintf(stderr, "Unable to open file: %s\n", cdtrack_info.track[i].fname.c_str()); + osd_printf_error("Unable to open file: %s\n", cdtrack_info.track[i].fname); throw nullptr; } fhandle[i] = util::osd_file_read(std::move(file)); if (!fhandle[i]) { - fprintf(stderr, "Unable to open file: %s\n", cdtrack_info.track[i].fname.c_str()); + osd_printf_error("Unable to open file: %s\n", cdtrack_info.track[i].fname); throw nullptr; } } @@ -204,6 +181,9 @@ cdrom_file::cdrom_file(std::string_view inputfile) track.logframeofs = track.pregap; } + if ((cdtoc.flags & CD_FLAG_MULTISESSION) && (cdtrack_info.track[i].leadin != -1)) + logofs += cdtrack_info.track[i].leadin; + track.physframeofs = physofs; track.chdframeofs = 0; track.logframeofs += logofs; @@ -215,22 +195,30 @@ cdrom_file::cdrom_file(std::string_view inputfile) physofs += track.frames; logofs += track.frames; + if ((cdtoc.flags & CD_FLAG_MULTISESSION) && cdtrack_info.track[i].leadout != -1) + logofs += cdtrack_info.track[i].leadout; + if (EXTRA_VERBOSE) - printf("Track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d\n", i+1, - track.trktype, - track.subtype, - track.datasize, - track.subsize, - track.frames, - track.extraframes, - track.pregap, - track.pgtype, - track.pgdatasize, - track.postgap, - track.logframeofs, - track.physframeofs, - track.chdframeofs, - track.logframes); + { + osd_printf_verbose("session %d track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n", + track.session + 1, + i + 1, + track.trktype, + track.subtype, + track.datasize, + track.subsize, + track.frames, + track.extraframes, + track.pregap, + track.pgtype, + track.pgdatasize, + track.postgap, + track.logframeofs, + track.physframeofs, + track.chdframeofs, + track.logframes, + track.padframes); + } } // fill out dummy entries for the last track to help our search @@ -313,21 +301,26 @@ cdrom_file::cdrom_file(chd_file *_chd) logofs += track.frames; if (EXTRA_VERBOSE) - printf("Track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d\n", i+1, - track.trktype, - track.subtype, - track.datasize, - track.subsize, - track.frames, - track.extraframes, - track.pregap, - track.pgtype, - track.pgdatasize, - track.postgap, - track.logframeofs, - track.physframeofs, - track.chdframeofs, - track.logframes); + { + osd_printf_verbose("session %d track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d pregap %d pgmode %d presize %d postgap %d logofs %d physofs %d chdofs %d logframes %d pad %d\n", + track.session + 1, + i + 1, + track.trktype, + track.subtype, + track.datasize, + track.subsize, + track.frames, + track.extraframes, + track.pregap, + track.pgtype, + track.pgdatasize, + track.postgap, + track.logframeofs, + track.physframeofs, + track.chdframeofs, + track.logframes, + track.padframes); + } } // fill out dummy entries for the last track to help our search @@ -387,7 +380,7 @@ std::error_condition cdrom_file::read_partial_sector(void *dest, uint32_t lbasec if ((cdtoc.tracks[tracknum].pgdatasize == 0) && (lbasector < cdtoc.tracks[tracknum].logframeofs)) { if (EXTRA_VERBOSE) - printf("PG missing sector: LBA %d, trklog %d\n", lbasector, cdtoc.tracks[tracknum].logframeofs); + osd_printf_verbose("PG missing sector: LBA %d, trklog %d\n", lbasector, cdtoc.tracks[tracknum].logframeofs); memset(dest, 0, length); return result; } @@ -423,13 +416,13 @@ std::error_condition cdrom_file::read_partial_sector(void *dest, uint32_t lbasec sourcefileoffset += chdsector * bytespersector + startoffs; if (EXTRA_VERBOSE) - printf("Reading %u bytes from sector %d from track %d at offset %lu\n", (unsigned)length, chdsector, tracknum + 1, (unsigned long)sourcefileoffset); + osd_printf_verbose("Reading %u bytes from sector %d from track %d at offset %lu\n", (unsigned)length, chdsector, tracknum + 1, (unsigned long)sourcefileoffset); - size_t actual; result = srcfile.seek(sourcefileoffset, SEEK_SET); + size_t actual; if (!result) - result = srcfile.read(dest, length, actual); - // FIXME: if (actual < length) report error + std::tie(result, actual) = read(srcfile, dest, length); + // FIXME: if (!result && (actual < length)) report error needswap = cdtrack_info.track[tracknum].swap; } @@ -437,9 +430,10 @@ std::error_condition cdrom_file::read_partial_sector(void *dest, uint32_t lbasec if (needswap) { uint8_t *buffer = (uint8_t *)dest - startoffs; - for (int swapindex = startoffs; swapindex < 2352; swapindex += 2 ) + for (int swapindex = startoffs; swapindex < 2352; swapindex += 2) { - std::swap(buffer[ swapindex ], buffer[ swapindex + 1 ]); + using std::swap; + swap(buffer[ swapindex ], buffer[ swapindex + 1 ]); } } return result; @@ -604,6 +598,27 @@ uint32_t cdrom_file::get_track(uint32_t frame) const return track; } +uint32_t cdrom_file::get_track_index(uint32_t frame) const +{ + const uint32_t track = get_track(frame); + const uint32_t track_start = get_track_start(track); + const uint32_t index_offset = frame - track_start; + int index = 0; + + for (int i = 0; i < std::size(cdtrack_info.track[track].idx); i++) + { + if (index_offset >= cdtrack_info.track[track].idx[i]) + index = i; + else + break; + } + + if (cdtrack_info.track[track].idx[index] == -1) + index = 1; // valid index not found, default to index 1 + + return index; +} + /*************************************************************************** EXTRA UTILITIES @@ -682,11 +697,6 @@ void cdrom_file::get_info_from_type_string(const char *typestring, uint32_t *trk *trktype = CD_TRACK_MODE2_FORM_MIX; *datasize = 2336; } - else if (!strcmp(typestring, "MODE2/2336")) - { - *trktype = CD_TRACK_MODE2_FORM_MIX; - *datasize = 2336; - } else if (!strcmp(typestring, "MODE2_RAW")) { *trktype = CD_TRACK_MODE2_RAW; @@ -891,91 +901,78 @@ std::error_condition cdrom_file::parse_metadata(chd_file *chd, toc &toc) std::string metadata; std::error_condition err; - toc.flags = 0; + /* clear structures */ + memset(&toc, 0, sizeof(toc)); + + toc.numsessions = 1; /* start with no tracks */ for (toc.numtrks = 0; toc.numtrks < MAX_TRACKS; toc.numtrks++) { - int tracknum = -1, frames = 0, pregap, postgap, padframes; + int tracknum, frames, pregap, postgap, padframes; char type[16], subtype[16], pgtype[16], pgsub[16]; track_info *track; - pregap = postgap = padframes = 0; + tracknum = -1; + frames = pregap = postgap = padframes = 0; + std::fill(std::begin(type), std::end(type), 0); + std::fill(std::begin(subtype), std::end(subtype), 0); + std::fill(std::begin(pgtype), std::end(pgtype), 0); + std::fill(std::begin(pgsub), std::end(pgsub), 0); - /* fetch the metadata for this track */ - err = chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc.numtrks, metadata); - if (!err) + // fetch the metadata for this track + if (!chd->read_metadata(CDROM_TRACK_METADATA_TAG, toc.numtrks, metadata)) { - /* 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 chd_file::error::INVALID_DATA; - if (tracknum == 0 || tracknum > MAX_TRACKS) + } + else if (!chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc.numtrks, metadata)) + { + if (sscanf(metadata.c_str(), CDROM_TRACK_METADATA2_FORMAT, &tracknum, type, subtype, &frames, &pregap, pgtype, pgsub, &postgap) != 8) return chd_file::error::INVALID_DATA; - track = &toc.tracks[tracknum - 1]; } else { - err = chd->read_metadata(CDROM_TRACK_METADATA2_TAG, toc.numtrks, metadata); + // fall through to GD-ROM detection + err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc.numtrks, metadata); 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 chd_file::error::INVALID_DATA; - if (tracknum == 0 || tracknum > MAX_TRACKS) - return chd_file::error::INVALID_DATA; - track = &toc.tracks[tracknum - 1]; - } + toc.flags |= CD_FLAG_GDROMLE; // legacy GDROM track was detected else - { - err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc.numtrks, metadata); - if (!err) - /* legacy GDROM track was detected */ - toc.flags |= CD_FLAG_GDROMLE; - else - err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc.numtrks, metadata); + err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc.numtrks, metadata); - 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 chd_file::error::INVALID_DATA; - if (tracknum == 0 || tracknum > MAX_TRACKS) - return chd_file::error::INVALID_DATA; - track = &toc.tracks[tracknum - 1]; - toc.flags |= CD_FLAG_GDROM; - } - else - { - break; - } - } + if (err) + break; + + if (sscanf(metadata.c_str(), GDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames, &padframes, &pregap, pgtype, pgsub, &postgap) != 9) + return chd_file::error::INVALID_DATA; + + toc.flags |= CD_FLAG_GDROM; } - /* extract the track type and determine the data size */ + if (tracknum == 0 || tracknum > MAX_TRACKS) + return chd_file::error::INVALID_DATA; + + track = &toc.tracks[tracknum - 1]; + + // extract the track type and determine the data size track->trktype = CD_TRACK_MODE1; track->datasize = 0; convert_type_string_to_track_info(type, track); if (track->datasize == 0) return chd_file::error::INVALID_DATA; - /* extract the subtype and determine the subcode data size */ + // extract the subtype and determine the subcode data size track->subtype = CD_SUB_NONE; track->subsize = 0; convert_subtype_string_to_track_info(subtype, track); - /* set the frames and extra frames data */ + // set the frames and extra frames data track->frames = frames; track->padframes = padframes; int padded = (frames + TRACK_PADDING - 1) / TRACK_PADDING; track->extraframes = padded * TRACK_PADDING - frames; - /* set the pregap info */ + // set the pregap info track->pregap = pregap; track->pgtype = CD_TRACK_MODE1; track->pgsub = CD_SUB_NONE; @@ -999,7 +996,7 @@ std::error_condition cdrom_file::parse_metadata(chd_file *chd, toc &toc) if (toc.numtrks > 0) return std::error_condition(); - printf("toc.numtrks = %u?!\n", toc.numtrks); + osd_printf_info("toc.numtrks = %u?!\n", toc.numtrks); /* look for old-style metadata */ std::vector<uint8_t> oldmetadata; @@ -1011,8 +1008,11 @@ std::error_condition cdrom_file::parse_metadata(chd_file *chd, toc &toc) auto *mrp = reinterpret_cast<uint32_t *>(&oldmetadata[0]); toc.numtrks = *mrp++; + toc.numsessions = 1; + for (int i = 0; i < MAX_TRACKS; i++) { + toc.tracks[i].session = 0; toc.tracks[i].trktype = *mrp++; toc.tracks[i].subtype = *mrp++; toc.tracks[i].datasize = *mrp++; @@ -1070,7 +1070,16 @@ std::error_condition cdrom_file::write_metadata(chd_file *chd, const toc &toc) for (int i = 0; i < toc.numtrks; i++) { std::string metadata; - if (!(toc.flags & CD_FLAG_GDROM)) + if (toc.flags & CD_FLAG_GDROM) + { + metadata = util::string_format(GDROM_TRACK_METADATA_FORMAT, i + 1, get_type_string(toc.tracks[i].trktype), + get_subtype_string(toc.tracks[i].subtype), toc.tracks[i].frames, toc.tracks[i].padframes, + toc.tracks[i].pregap, get_type_string(toc.tracks[i].pgtype), + get_subtype_string(toc.tracks[i].pgsub), toc.tracks[i].postgap); + + err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata); + } + else { char submode[32]; @@ -1090,15 +1099,6 @@ std::error_condition cdrom_file::write_metadata(chd_file *chd, const toc &toc) toc.tracks[i].postgap); err = chd->write_metadata(CDROM_TRACK_METADATA2_TAG, i, metadata); } - else - { - metadata = util::string_format(GDROM_TRACK_METADATA_FORMAT, i + 1, get_type_string(toc.tracks[i].trktype), - get_subtype_string(toc.tracks[i].subtype), toc.tracks[i].frames, toc.tracks[i].padframes, - toc.tracks[i].pregap, get_type_string(toc.tracks[i].pgtype), - get_subtype_string(toc.tracks[i].pgsub), toc.tracks[i].postgap); - - err = chd->write_metadata(GDROM_TRACK_METADATA_TAG, i, metadata); - } if (err) return err; } @@ -1440,14 +1440,14 @@ void cdrom_file::ecc_clear(uint8_t *sector) * * @brief A macro that defines tokenize. * - * @param linebuffer The linebuffer. - * @param i Zero-based index of the. - * @param sizeof(linebuffer) The sizeof(linebuffer) - * @param token The token. - * @param sizeof(token) The sizeof(token) + * @param linebuffer The linebuffer. + * @param i Zero-based index of the. + * @param std::size(linebuffer) The std::size(linebuffer) + * @param token The token. + * @param std::size(token) The std::size(token) */ -#define TOKENIZE i = tokenize( linebuffer, i, sizeof(linebuffer), token, sizeof(token) ); +#define TOKENIZE i = tokenize( linebuffer, i, std::size(linebuffer), token, std::size(token) ); /*************************************************************************** @@ -1467,9 +1467,12 @@ void cdrom_file::ecc_clear(uint8_t *sector) std::string cdrom_file::get_file_path(std::string &path) { int pos = path.find_last_of('\\'); - if (pos!=-1) { + if (pos!=-1) + { path = path.substr(0,pos+1); - } else { + } + else + { pos = path.find_last_of('/'); path = path.substr(0,pos+1); } @@ -1518,20 +1521,20 @@ uint64_t cdrom_file::get_file_size(std::string_view filename) * @return An int. */ -int cdrom_file::tokenize( const char *linebuffer, int i, int linebuffersize, char *token, int tokensize ) +int cdrom_file::tokenize(const char *linebuffer, int i, int linebuffersize, char *token, int tokensize) { int j = 0; - int singlequote = 0; - int doublequote = 0; + bool singlequote = false; + bool doublequote = false; while ((i < linebuffersize) && isspace((uint8_t)linebuffer[i])) { i++; } - while ((i < linebuffersize) && (j < tokensize)) + while ((i < linebuffersize) && (j < tokensize) && (linebuffer[i] != '\0')) { - if (!singlequote && linebuffer[i] == '"' ) + if (!singlequote && linebuffer[i] == '"') { doublequote = !doublequote; } @@ -1572,19 +1575,19 @@ int cdrom_file::tokenize( const char *linebuffer, int i, int linebuffersize, cha * @return An int. */ -int cdrom_file::msf_to_frames( char *token ) +int cdrom_file::msf_to_frames(const char *token) { int m = 0; int s = 0; int f = 0; - if( sscanf( token, "%d:%d:%d", &m, &s, &f ) == 1 ) + if (sscanf(token, "%d:%d:%d", &m, &s, &f) == 1) { f = m; } else { - /* convert to just frames */ + // convert to just frames s += (m * 60); f += (s * 75); } @@ -1624,7 +1627,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao std::error_condition const filerr = osd_file::open(fname, OPEN_FLAG_READ, file, fsize); if (filerr) { - printf("ERROR: could not open (%s)\n", fname.c_str()); + osd_printf_error("ERROR: could not open (%s)\n", fname); return 0; } @@ -1633,12 +1636,12 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao offset += actual; if (offset < 4) { - printf("ERROR: unexpected RIFF offset %lu (%s)\n", offset, fname.c_str()); + osd_printf_error("ERROR: unexpected RIFF offset %lu (%s)\n", offset, fname); return 0; } if (memcmp(&buf[0], "RIFF", 4) != 0) { - printf("ERROR: could not find RIFF header (%s)\n", fname.c_str()); + osd_printf_error("ERROR: could not find RIFF header (%s)\n", fname); return 0; } @@ -1647,7 +1650,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao offset += actual; if (offset < 8) { - printf("ERROR: unexpected size offset %lu (%s)\n", offset, fname.c_str()); + osd_printf_error("ERROR: unexpected size offset %lu (%s)\n", offset, fname); return 0; } filesize = little_endianize_int32(filesize); @@ -1657,12 +1660,12 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao offset += actual; if (offset < 12) { - printf("ERROR: unexpected WAVE offset %lu (%s)\n", offset, fname.c_str()); + osd_printf_error("ERROR: unexpected WAVE offset %lu (%s)\n", offset, fname); return 0; } if (memcmp(&buf[0], "WAVE", 4) != 0) { - printf("ERROR: could not find WAVE header (%s)\n", fname.c_str()); + osd_printf_error("ERROR: could not find WAVE header (%s)\n", fname); return 0; } @@ -1681,7 +1684,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao offset += length; if (offset >= filesize) { - printf("ERROR: could not find fmt tag (%s)\n", fname.c_str()); + osd_printf_error("ERROR: could not find fmt tag (%s)\n", fname); return 0; } } @@ -1692,7 +1695,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao temp16 = little_endianize_int16(temp16); if (temp16 != 1) { - printf("ERROR: unsupported format %u - only PCM is supported (%s)\n", temp16, fname.c_str()); + osd_printf_error("ERROR: unsupported format %u - only PCM is supported (%s)\n", temp16, fname); return 0; } @@ -1702,7 +1705,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao temp16 = little_endianize_int16(temp16); if (temp16 != 2) { - printf("ERROR: unsupported number of channels %u - only stereo is supported (%s)\n", temp16, fname.c_str()); + osd_printf_error("ERROR: unsupported number of channels %u - only stereo is supported (%s)\n", temp16, fname); return 0; } @@ -1712,7 +1715,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao rate = little_endianize_int32(rate); if (rate != 44100) { - printf("ERROR: unsupported samplerate %u - only 44100 is supported (%s)\n", rate, fname.c_str()); + osd_printf_error("ERROR: unsupported samplerate %u - only 44100 is supported (%s)\n", rate, fname); return 0; } @@ -1726,7 +1729,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao bits = little_endianize_int16(bits); if (bits != 16) { - printf("ERROR: unsupported bits/sample %u - only 16 is supported (%s)\n", bits, fname.c_str()); + osd_printf_error("ERROR: unsupported bits/sample %u - only 16 is supported (%s)\n", bits, fname); return 0; } @@ -1748,7 +1751,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao offset += length; if (offset >= filesize) { - printf("ERROR: could not find data tag (%s)\n", fname.c_str()); + osd_printf_error("ERROR: could not find data tag (%s)\n", fname); return 0; } } @@ -1756,7 +1759,7 @@ uint32_t cdrom_file::parse_wav_sample(std::string_view filename, uint32_t *datao /* if there was a 0 length data block, we're done */ if (length == 0) { - printf("ERROR: empty data block (%s)\n", fname.c_str()); + osd_printf_error("ERROR: empty data block (%s)\n", fname); return 0; } @@ -1858,13 +1861,15 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt memset(&outtoc, 0, sizeof(outtoc)); outinfo.reset(); + outtoc.numsessions = 1; + // seek to 12 bytes before the end fseek(infile, -12, SEEK_END); fread(buffer, 12, 1, infile); if (memcmp(buffer, "NER5", 4)) { - printf("ERROR: Not a Nero 5.5 or later image!\n"); + osd_printf_error("ERROR: Not a Nero 5.5 or later image!\n"); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; } @@ -1873,7 +1878,7 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt if ((buffer[7] != 0) || (buffer[6] != 0) || (buffer[5] != 0) || (buffer[4] != 0)) { - printf("ERROR: File size is > 4GB, this version of CHDMAN cannot handle it."); + osd_printf_error("ERROR: File size is > 4GB, this version of CHDMAN cannot handle it."); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; } @@ -1920,8 +1925,7 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt // printf("Track %d: sector size %d mode %x index0 %llx index1 %llx track_end %llx (pregap %d sectors, length %d sectors)\n", track, size, mode, index0, index1, track_end, (uint32_t)(index1-index0)/size, (uint32_t)(track_end-index1)/size); outinfo.track[track-1].fname.assign(tocfname); outinfo.track[track-1].offset = offset + (uint32_t)(index1-index0); - outinfo.track[track-1].idx0offs = 0; - outinfo.track[track-1].idx1offs = 0; + outinfo.track[track-1].idx[0] = outinfo.track[track-1].idx[1] = 0; switch (mode) { @@ -1931,12 +1935,12 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt break; case 0x0300: // Mode 2 Form 1 - printf("ERROR: Mode 2 Form 1 tracks not supported\n"); + osd_printf_error("ERROR: Mode 2 Form 1 tracks not supported\n"); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; case 0x0500: // raw data - printf("ERROR: Raw data tracks not supported\n"); + osd_printf_error("ERROR: Raw data tracks not supported\n"); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; @@ -1951,22 +1955,22 @@ std::error_condition cdrom_file::parse_nero(std::string_view tocfname, toc &outt break; case 0x0f00: // raw data with sub-channel - printf("ERROR: Raw data tracks with sub-channel not supported\n"); + osd_printf_error("ERROR: Raw data tracks with sub-channel not supported\n"); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; case 0x1000: // audio with sub-channel - printf("ERROR: Audio tracks with sub-channel not supported\n"); + osd_printf_error("ERROR: Audio tracks with sub-channel not supported\n"); fclose(infile); 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"); + osd_printf_error("ERROR: Raw Mode 2 Form 1 tracks with sub-channel not supported\n"); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; default: - printf("ERROR: Unknown track type %x, contact MAMEDEV!\n", mode); + osd_printf_error("ERROR: Unknown track type %x, contact MAMEDEV!\n", mode); fclose(infile); return chd_file::error::UNSUPPORTED_FORMAT; } @@ -2041,31 +2045,38 @@ std::error_condition cdrom_file::parse_iso(std::string_view tocfname, toc &outto outtoc.numtrks = 1; + outtoc.numsessions = 1; outinfo.track[0].fname = tocfname; outinfo.track[0].offset = 0; - outinfo.track[0].idx0offs = 0; - outinfo.track[0].idx1offs = 0; + outinfo.track[0].idx[0] = outinfo.track[0].idx[1] = 0; - if ((size % 2048)==0 ) { + if ((size % 2048) == 0) + { outtoc.tracks[0].trktype = CD_TRACK_MODE1; outtoc.tracks[0].frames = size / 2048; outtoc.tracks[0].datasize = 2048; outinfo.track[0].swap = false; - } else if ((size % 2336)==0 ) { + } + else if ((size % 2336) == 0) + { // 2352 byte mode 2 outtoc.tracks[0].trktype = CD_TRACK_MODE2; outtoc.tracks[0].frames = size / 2336; outtoc.tracks[0].datasize = 2336; outinfo.track[0].swap = false; - } else if ((size % 2352)==0 ) { + } + else if ((size % 2352) == 0) + { // 2352 byte mode 2 raw outtoc.tracks[0].trktype = CD_TRACK_MODE2_RAW; outtoc.tracks[0].frames = size / 2352; outtoc.tracks[0].datasize = 2352; outinfo.track[0].swap = false; - } else { - printf("ERROR: Unrecognized track type\n"); + } + else + { + osd_printf_error("ERROR: Unrecognized track type\n"); return chd_file::error::UNSUPPORTED_FORMAT; } @@ -2103,7 +2114,9 @@ std::error_condition cdrom_file::parse_iso(std::string_view tocfname, toc &outto std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outtoc, track_input_info &outinfo) { - int i, numtracks; + char token[512]; + int i = 0; + int trackcnt = 0; std::string path = std::string(tocfname); @@ -2122,89 +2135,172 @@ std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outto outtoc.flags = CD_FLAG_GDROM; char linebuffer[512]; - fgets(linebuffer,511,infile); - numtracks=atoi(linebuffer); + memset(linebuffer, 0, sizeof(linebuffer)); + + if (!fgets(linebuffer,511,infile)) + { + osd_printf_error("GDI doesn't have track count (blank file?)\n"); + return chd_file::error::INVALID_DATA; + } + + i = 0; + TOKENIZE + + const int numtracks = atoi(token); + + if (numtracks > 0 && numtracks - 1 > std::size(outinfo.track)) + { + osd_printf_error("GDI expects too many tracks. Expected %d tracks but only up to %zu tracks allowed\n", numtracks, std::size(outinfo.track) + 1); + return chd_file::error::INVALID_DATA; + } - for(i=0;i<numtracks;++i) + if (numtracks == 0) { - char *tok; - int trknum; - int trksize,trktype; - int sz; + osd_printf_error("GDI header specifies no tracks\n"); + return chd_file::error::INVALID_DATA; + } - fgets(linebuffer,511,infile); + while (!feof(infile)) + { + int paramcnt = 0; - tok=strtok(linebuffer," "); + if (!fgets(linebuffer,511,infile)) + break; - trknum=atoi(tok)-1; + i = 0; + TOKENIZE - outinfo.track[trknum].swap=false; - outinfo.track[trknum].offset=0; + // Ignore empty lines so they're not countered toward the total track count + if (!token[0]) + continue; + + paramcnt++; + const int trknum = atoi(token) - 1; + + if (trknum < 0 || trknum > std::size(outinfo.track) || trknum + 1 > numtracks) + { + osd_printf_error("Track %d is out of expected range of 1 to %d\n", trknum + 1, numtracks); + return chd_file::error::INVALID_DATA; + } + + if (outtoc.tracks[trknum].datasize != 0) + osd_printf_warning("Track %d defined multiple times?\n", trknum + 1); + else + trackcnt++; + + outinfo.track[trknum].swap = false; + outinfo.track[trknum].offset = 0; outtoc.tracks[trknum].datasize = 0; outtoc.tracks[trknum].subtype = CD_SUB_NONE; outtoc.tracks[trknum].subsize = 0; outtoc.tracks[trknum].pgsub = CD_SUB_NONE; - tok=strtok(nullptr," "); - outtoc.tracks[trknum].physframeofs=atoi(tok); + TOKENIZE + if (token[0]) + paramcnt++; + outtoc.tracks[trknum].physframeofs = atoi(token); - tok=strtok(nullptr," "); - trktype=atoi(tok); + TOKENIZE + if (token[0]) + paramcnt++; + const int trktype = atoi(token); - tok=strtok(nullptr," "); - trksize=atoi(tok); + TOKENIZE + if (token[0]) + paramcnt++; + const int trksize = atoi(token); - if(trktype==4 && trksize==2352) + if (trktype == 4 && trksize == 2352) { - outtoc.tracks[trknum].trktype=CD_TRACK_MODE1_RAW; - outtoc.tracks[trknum].datasize=2352; + outtoc.tracks[trknum].trktype = CD_TRACK_MODE1_RAW; + outtoc.tracks[trknum].datasize = 2352; } - if(trktype==4 && trksize==2048) + else if (trktype == 4 && trksize == 2048) { - outtoc.tracks[trknum].trktype=CD_TRACK_MODE1; - outtoc.tracks[trknum].datasize=2048; + outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; + outtoc.tracks[trknum].datasize = 2048; } - if(trktype==0) + else if (trktype == 0) { - outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO; - outtoc.tracks[trknum].datasize=2352; + outtoc.tracks[trknum].trktype = CD_TRACK_AUDIO; + outtoc.tracks[trknum].datasize = 2352; outinfo.track[trknum].swap = true; } + else + { + osd_printf_error("Unknown track type %d and track size %d combination encountered\n", trktype, trksize); + return chd_file::error::INVALID_DATA; + } - std::string name; + // skip to start of next token + int pi = i; + while (pi < std::size(linebuffer) && isspace((uint8_t)linebuffer[pi])) + pi++; - tok=strtok(nullptr," "); - name = tok; - if (tok[0]=='"') { - do { - tok=strtok(nullptr," "); - if (tok!=nullptr) { - name += " "; - name += tok; - } - } while(tok!=nullptr && (strrchr(tok,'"')-tok !=(strlen(tok)-1))); - strdelchr(name,'"'); + if (linebuffer[pi] == '"' && strchr(linebuffer + pi + 1, '"') == nullptr) + { + osd_printf_error("Track %d filename does not having closing quotation mark: '%s'\n", trknum + 1, linebuffer + pi); + return chd_file::error::INVALID_DATA; } - outinfo.track[trknum].fname.assign(path).append(name); - sz = get_file_size(outinfo.track[trknum].fname); + TOKENIZE + if (token[0]) + paramcnt++; + + outinfo.track[trknum].fname.assign(path).append(token); - outtoc.tracks[trknum].frames = sz/trksize; + const uint64_t sz = get_file_size(outinfo.track[trknum].fname); + outtoc.tracks[trknum].frames = sz / trksize; outtoc.tracks[trknum].padframes = 0; if (trknum != 0) { - int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs); + const int dif = outtoc.tracks[trknum].physframeofs - (outtoc.tracks[trknum-1].frames + outtoc.tracks[trknum-1].physframeofs); outtoc.tracks[trknum-1].frames += dif; outtoc.tracks[trknum-1].padframes = dif; } + + TOKENIZE + // offset parameter, not used + if (token[0]) + paramcnt++; + + // check if there are any extra parameters that shouldn't be there + while (token[0]) + { + TOKENIZE + if (token[0]) + paramcnt++; + } + + if (paramcnt != 6) + { + osd_printf_error("GDI track entry should have 6 parameters, found %d\n", paramcnt); + return chd_file::error::INVALID_DATA; + } + } + + bool missing_tracks = trackcnt != numtracks; + for (int i = 0; i < numtracks; i++) + { + if (outtoc.tracks[i].datasize == 0) + { + osd_printf_warning("Could not find track %d\n", i + 1); + missing_tracks = true; + } + } + + if (missing_tracks) + { + osd_printf_error("GDI is missing tracks\n"); + return chd_file::error::INVALID_DATA; } if (EXTRA_VERBOSE) - for(i=0; i < numtracks; i++) + for (int i = 0; i < numtracks; i++) { - printf("%s %d %d %d (true %d)\n", outinfo.track[i].fname.c_str(), outtoc.tracks[i].frames, outtoc.tracks[i].padframes, outtoc.tracks[i].physframeofs, outtoc.tracks[i].frames - outtoc.tracks[i].padframes); + osd_printf_verbose("'%s' %d %d %d (true %d)\n", outinfo.track[i].fname, outtoc.tracks[i].frames, outtoc.tracks[i].padframes, outtoc.tracks[i].physframeofs, outtoc.tracks[i].frames - outtoc.tracks[i].padframes); } /* close the input TOC */ @@ -2212,12 +2308,13 @@ std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outto /* store the number of tracks found */ outtoc.numtrks = numtracks; + outtoc.numsessions = 1; return std::error_condition(); } /*------------------------------------------------- - parse_cue - parse a CDRWin format CUE file + parse_cue - parse a .CUE file -------------------------------------------------*/ /** @@ -2230,15 +2327,23 @@ std::error_condition cdrom_file::parse_gdi(std::string_view tocfname, toc &outto * @param [in,out] outinfo The outinfo. * * @return A std::error_condition. + * + * Redump multi-CUE for Dreamcast GDI: + * 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. */ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo) { - int i, trknum; - static char token[512]; + int i, trknum, sessionnum, session_pregap; + char token[512]; std::string lastfname; uint32_t wavlen, wavoffs; std::string path = std::string(tocfname); + const bool is_gdrom = is_gdicue(tocfname); + enum gdi_area current_area = SINGLE_DENSITY; + bool is_multibin = false; + int leadin = -1; FILE *infile = fopen(path.c_str(), "rt"); if (!infile) @@ -2254,554 +2359,289 @@ std::error_condition cdrom_file::parse_cue(std::string_view tocfname, toc &outto trknum = -1; wavoffs = wavlen = 0; + sessionnum = 0; + session_pregap = 0; + + if (is_gdrom) + { + outtoc.flags = CD_FLAG_GDROM; + } char linebuffer[512]; + memset(linebuffer, 0, sizeof(linebuffer)); + while (!feof(infile)) { /* get the next line */ - fgets(linebuffer, 511, infile); + if (!fgets(linebuffer, 511, infile)) + break; - /* if EOF didn't hit, keep going */ - if (!feof(infile)) - { - i = 0; + i = 0; - TOKENIZE + TOKENIZE + + if (!strcmp(token, "REM")) + { + /* skip to actual data of REM command */ + while (i < std::size(linebuffer) && isspace((uint8_t)linebuffer[i])) + i++; - if (!strcmp(token, "FILE")) + if (!strncmp(linebuffer+i, "SESSION", 7)) { - /* found the data file for a track */ + /* IsoBuster extension */ TOKENIZE - /* keep the filename */ - lastfname.assign(path).append(token); - - /* get the file type */ + /* get the session number */ TOKENIZE - if (!strcmp(token, "BINARY")) - { - outinfo.track[trknum+1].swap = false; - } - else if (!strcmp(token, "MOTOROLA")) - { - outinfo.track[trknum+1].swap = true; - } - else if (!strcmp(token, "WAVE")) - { - wavlen = parse_wav_sample(lastfname, &wavoffs); - if (!wavlen) - { - fclose(infile); - printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str()); - return chd_file::error::INVALID_DATA; - } - } - else - { - fclose(infile); - printf("ERROR: Unhandled track type %s\n", token); - return chd_file::error::UNSUPPORTED_FORMAT; - } + sessionnum = strtoul(token, nullptr, 10) - 1; + + if (sessionnum >= 1) /* don't consider it a multisession CD unless there's actually more than 1 session */ + outtoc.flags |= CD_FLAG_MULTISESSION; } - else if (!strcmp(token, "TRACK")) + else if ((outtoc.flags & CD_FLAG_MULTISESSION) && !strncmp(linebuffer+i, "PREGAP", 6)) { - /* get the track number */ - TOKENIZE - trknum = strtoul(token, nullptr, 10) - 1; + /* + Redump extension? PREGAP associated with the session instead of the track - /* next token on the line is the track type */ + DiscImageCreator - Older versions would write a bogus value here (and maybe session lead-in and lead-out). + These should be considered bad dumps and will not be supported. + */ TOKENIZE - if (wavlen != 0) - { - outtoc.tracks[trknum].trktype = CD_TRACK_AUDIO; - outtoc.tracks[trknum].frames = wavlen/2352; - outinfo.track[trknum].offset = wavoffs; - wavoffs = wavlen = 0; - } - else - { - outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; - outtoc.tracks[trknum].datasize = 0; - outinfo.track[trknum].offset = 0; - } - outtoc.tracks[trknum].subtype = CD_SUB_NONE; - outtoc.tracks[trknum].subsize = 0; - outtoc.tracks[trknum].pgsub = CD_SUB_NONE; - outtoc.tracks[trknum].pregap = 0; - outtoc.tracks[trknum].padframes = 0; - outinfo.track[trknum].idx0offs = -1; - outinfo.track[trknum].idx1offs = 0; - - outinfo.track[trknum].fname.assign(lastfname); // default filename to the last one - -// printf("trk %d: fname %s offset %d\n", trknum, outinfo.track[trknum].fname.c_str(), outinfo.track[trknum].offset); - - convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); - if (outtoc.tracks[trknum].datasize == 0) - { - fclose(infile); - printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return chd_file::error::UNSUPPORTED_FORMAT; - } - - /* next (optional) token on the line is the subcode type */ + /* get pregap time */ TOKENIZE - - convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]); + session_pregap = msf_to_frames(token); } - else if (!strcmp(token, "INDEX")) /* only in bin/cue files */ + else if (!strncmp(linebuffer+i, "LEAD-OUT", 8)) { - int idx, frames; + /* + IsoBuster and ImgBurn (single bin file) - Lead-out time is the start of the lead-out + lead-out time - MSF of last track of session = size of last track - /* get index number */ + Redump and DiscImageCreator (multiple bins) - Lead-out time is the duration of just the lead-out + */ TOKENIZE - idx = strtoul(token, nullptr, 10); - /* get index */ + /* get lead-out time */ TOKENIZE - frames = msf_to_frames( token ); - - if (idx == 0) - { - outinfo.track[trknum].idx0offs = frames; - } - else if (idx == 1) - { - outinfo.track[trknum].idx1offs = frames; - if ((outtoc.tracks[trknum].pregap == 0) && (outinfo.track[trknum].idx0offs != -1)) - { - outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx0offs; - outtoc.tracks[trknum].pgtype = outtoc.tracks[trknum].trktype; - switch (outtoc.tracks[trknum].pgtype) - { - case CD_TRACK_MODE1: - case CD_TRACK_MODE2_FORM1: - outtoc.tracks[trknum].pgdatasize = 2048; - break; - - case CD_TRACK_MODE1_RAW: - case CD_TRACK_MODE2_RAW: - case CD_TRACK_AUDIO: - outtoc.tracks[trknum].pgdatasize = 2352; - break; - - case CD_TRACK_MODE2: - case CD_TRACK_MODE2_FORM_MIX: - outtoc.tracks[trknum].pgdatasize = 2336; - break; - - case CD_TRACK_MODE2_FORM2: - outtoc.tracks[trknum].pgdatasize = 2324; - break; - } - } - else // pregap sectors not in file, but we're always using idx0ofs for track length calc now - { - outinfo.track[trknum].idx0offs = frames; - } - } + int leadout_offset = msf_to_frames(token); + outinfo.track[trknum].leadout = leadout_offset; } - else if (!strcmp(token, "PREGAP")) + else if (!strncmp(linebuffer+i, "LEAD-IN", 7)) { - int frames; - - /* get index */ + /* + IsoBuster and ImgBurn (single bin file) - Not used? + Redump and DiscImageCreator (multiple bins) - Lead-in time is the duration of just the lead-in + */ TOKENIZE - frames = msf_to_frames( token ); - outtoc.tracks[trknum].pregap = frames; + /* get lead-in time */ + TOKENIZE + leadin = msf_to_frames(token); } - else if (!strcmp(token, "POSTGAP")) + else if (is_gdrom && !strncmp(linebuffer+i, "SINGLE-DENSITY AREA", 19)) { - int frames; - - /* get index */ - TOKENIZE - frames = msf_to_frames( token ); - - outtoc.tracks[trknum].postgap = frames; + /* single-density area starts LBA = 0 */ + current_area = SINGLE_DENSITY; + } + else if (is_gdrom && !strncmp(linebuffer+i, "HIGH-DENSITY AREA", 17)) + { + /* high-density area starts LBA = 45000 */ + current_area = HIGH_DENSITY; } } - } - - /* close the input CUE */ - fclose(infile); - - /* store the number of tracks found */ - outtoc.numtrks = trknum + 1; - - /* now go over the files again and set the lengths */ - for (trknum = 0; trknum < outtoc.numtrks; trknum++) - { - uint64_t tlen = 0; - - // this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian - if (outtoc.tracks[trknum].trktype == CD_TRACK_AUDIO) + else if (!strcmp(token, "FILE")) { - outinfo.track[trknum].swap = true; - } + /* found the data file for a track */ + TOKENIZE - // don't do this for .WAV tracks, we already have their length and offset filled out - if (outinfo.track[trknum].offset == 0) - { - // is this the last track? - if (trknum == (outtoc.numtrks-1)) + /* keep the filename */ + if (!is_multibin) { - /* if we have the same filename as the last track, do it that way */ - if (trknum != 0 && (outinfo.track[trknum].fname.compare(outinfo.track[trknum-1].fname)==0)) - { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) - { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - 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); - } - else /* data files are different */ - { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) - { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return std::errc::no_such_file_or_directory; - } - tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outtoc.tracks[trknum].frames = tlen; - outinfo.track[trknum].offset = 0; - } + std::string prevfname(std::move(lastfname)); + lastfname.assign(path).append(token); + is_multibin = !prevfname.empty() && lastfname != prevfname; } else { - /* if we have the same filename as the next track, do it that way */ - if (outinfo.track[trknum].fname.compare(outinfo.track[trknum+1].fname)==0) - { - outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx0offs - outinfo.track[trknum].idx0offs; + lastfname.assign(path).append(token); + } - if (trknum == 0) // track 0 offset is 0 - { - outinfo.track[trknum].offset = 0; - } - else - { - outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize); - } + /* get the file type */ + TOKENIZE - if (!outtoc.tracks[trknum].frames) - { - printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); - return chd_file::error::INVALID_DATA; - } - } - else /* data files are different */ + if (!strcmp(token, "BINARY")) + { + outinfo.track[trknum+1].swap = false; + } + else if (!strcmp(token, "MOTOROLA")) + { + outinfo.track[trknum+1].swap = true; + } + else if (!strcmp(token, "WAVE")) + { + wavlen = parse_wav_sample(lastfname, &wavoffs); + if (!wavlen) { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) - { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str()); - return std::errc::no_such_file_or_directory; - } - tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outtoc.tracks[trknum].frames = tlen; - outinfo.track[trknum].offset = 0; + fclose(infile); + osd_printf_error("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname); + return chd_file::error::INVALID_DATA; } } + else + { + fclose(infile); + osd_printf_error("ERROR: Unhandled track type %s\n", token); + return chd_file::error::UNSUPPORTED_FORMAT; + } } - //printf("trk %d: %d frames @ offset %d\n", trknum+1, outtoc.tracks[trknum].frames, outinfo.track[trknum].offset); - } - - return std::error_condition(); -} - -/*--------------------------------------------------------------------------------------- - is_gdicue - determine if CUE contains Redump multi-CUE format for Dreamcast GDI -----------------------------------------------------------------------------------------*/ - -/** - * Dreamcast GDI has two images on one disc, SINGLE-DENSITY and HIGH-DENSITY. - * - * Redump stores both images in a single .cue with a REM comment separating the images. - * This multi-cue format replaces the old flawed .gdi format. - * - * http://forum.redump.org/topic/19969/done-sega-dreamcast-multicue-gdi/ - * - * This function looks for strings "REM SINGLE-DENSITY AREA" & "REM HIGH-DENSITY AREA" - * indicating the Redump multi-cue format and therefore a Dreamcast GDI disc. - */ - -bool cdrom_file::is_gdicue(std::string_view tocfname) -{ - bool has_rem_singledensity = false; - bool has_rem_highdensity = false; - std::string path = std::string(tocfname); - - FILE *infile = fopen(path.c_str(), "rt"); - if (!infile) - { - return false; - } - - path = get_file_path(path); - - char linebuffer[512]; - while (!feof(infile)) - { - fgets(linebuffer, 511, infile); - - /* if EOF didn't hit, keep going */ - if (!feof(infile)) + else if (!strcmp(token, "TRACK")) { - has_rem_singledensity = has_rem_singledensity || !strncmp(linebuffer, "REM SINGLE-DENSITY AREA", 23); - has_rem_highdensity = has_rem_highdensity || !strncmp(linebuffer, "REM HIGH-DENSITY AREA", 21); - } - } - - fclose(infile); - - return has_rem_singledensity && has_rem_highdensity; -} - -/*----------------------------------------------------------------- - parse_gdicue - parse a Redump multi-CUE for Dreamcast GDI -------------------------------------------------------------------*/ - -/** - * @fn std::error_condition parse_gdicue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo) - * - * @brief Chdcd parse cue. - * - * @param tocfname The tocfname. - * @param [in,out] outtoc The outtoc. - * @param [in,out] outinfo The outinfo. - * - * @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. - * - * There are three Dreamcast disc patterns. - * - * Pattern I - (SD) DATA + AUDIO, (HD) DATA - * Pattern II - (SD) DATA + AUDIO, (HD) DATA + ... + AUDIO - * Pattern III - (SD) DATA + AUDIO, (HD) DATA + ... + DATA - * - * TOSEC layout is preferred and this code adjusts the TOC and INFO generated by a Redump .cue to match the - * layout from a TOSEC .gdi. - */ - -std::error_condition cdrom_file::parse_gdicue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo) -{ - int i, trknum; - static char token[512]; - std::string lastfname; - uint32_t wavlen, wavoffs; - std::string path = std::string(tocfname); - enum gdi_area current_area = SINGLE_DENSITY; - enum gdi_pattern disc_pattern = TYPE_UNKNOWN; - - FILE *infile = fopen(path.c_str(), "rt"); - if (!infile) - { - return std::error_condition(errno, std::generic_category()); - } - - path = get_file_path(path); - - /* clear structures */ - memset(&outtoc, 0, sizeof(outtoc)); - outinfo.reset(); - - trknum = -1; - wavoffs = wavlen = 0; - - outtoc.flags = CD_FLAG_GDROM; + /* get the track number */ + TOKENIZE + trknum = strtoul(token, nullptr, 10) - 1; - char linebuffer[512]; - while (!feof(infile)) - { - /* get the next line */ - fgets(linebuffer, 511, infile); + /* next token on the line is the track type */ + TOKENIZE - /* if EOF didn't hit, keep going */ - if (!feof(infile)) - { - /* single-density area starts LBA = 0 */ - if (!strncmp(linebuffer, "REM SINGLE-DENSITY AREA", 23)) + outtoc.tracks[trknum].session = sessionnum; + outtoc.tracks[trknum].subtype = CD_SUB_NONE; + outtoc.tracks[trknum].subsize = 0; + outtoc.tracks[trknum].pgsub = CD_SUB_NONE; + outtoc.tracks[trknum].pregap = 0; + outtoc.tracks[trknum].padframes = 0; + outtoc.tracks[trknum].datasize = 0; + outtoc.tracks[trknum].multicuearea = is_gdrom ? current_area : 0; + outinfo.track[trknum].offset = 0; + std::fill(std::begin(outinfo.track[trknum].idx), std::end(outinfo.track[trknum].idx), -1); + + outinfo.track[trknum].leadout = -1; + outinfo.track[trknum].leadin = leadin; /* use previously saved lead-in value */ + leadin = -1; + + if (session_pregap != 0) { - current_area = SINGLE_DENSITY; - continue; + /* + associated the pregap from the session transition with the lead-in to simplify things for now. + setting it as the proper pregap for the track causes logframeofs of the last dummy entry in the TOC + to become 2s later than it should. this might be an issue with how pgdatasize = 0 pregaps are handled. + */ + if (outinfo.track[trknum].leadin == -1) + outinfo.track[trknum].leadin = session_pregap; + else + outinfo.track[trknum].leadin += session_pregap; + session_pregap = 0; } - /* high-density area starts LBA = 45000 */ - if (!strncmp(linebuffer, "REM HIGH-DENSITY AREA", 21)) + if (wavlen != 0) { - current_area = HIGH_DENSITY; - continue; + outtoc.tracks[trknum].frames = wavlen/2352; + outinfo.track[trknum].offset = wavoffs; + wavoffs = wavlen = 0; } - i = 0; - - TOKENIZE + outinfo.track[trknum].fname.assign(lastfname); /* default filename to the last one */ - if (!strcmp(token, "FILE")) + if (EXTRA_VERBOSE) { - /* found the data file for a track */ - TOKENIZE - - /* keep the filename */ - lastfname.assign(path).append(token); - - /* get the file type */ - TOKENIZE - - if (!strcmp(token, "BINARY")) - { - outinfo.track[trknum+1].swap = false; - } - else if (!strcmp(token, "MOTOROLA")) + if (is_gdrom) { - outinfo.track[trknum+1].swap = true; - } - else if (!strcmp(token, "WAVE")) - { - wavlen = parse_wav_sample(lastfname, &wavoffs); - if (!wavlen) - { - fclose(infile); - printf("ERROR: couldn't read [%s] or not a valid .WAV\n", lastfname.c_str()); - return chd_file::error::INVALID_DATA; - } + osd_printf_verbose("trk %d: fname %s offset %d area %d\n", trknum, outinfo.track[trknum].fname, outinfo.track[trknum].offset, outtoc.tracks[trknum].multicuearea); } else { - fclose(infile); - printf("ERROR: Unhandled track type %s\n", token); - return chd_file::error::UNSUPPORTED_FORMAT; + osd_printf_verbose("trk %d: fname %s offset %d\n", trknum, outinfo.track[trknum].fname, outinfo.track[trknum].offset); } } - else if (!strcmp(token, "TRACK")) + + convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); + if (outtoc.tracks[trknum].datasize == 0) { - /* get the track number */ - TOKENIZE - trknum = strtoul(token, nullptr, 10) - 1; + fclose(infile); + osd_printf_error("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); + return chd_file::error::UNSUPPORTED_FORMAT; + } - /* next token on the line is the track type */ - TOKENIZE + /* next (optional) token on the line is the subcode type */ + TOKENIZE - if (wavlen != 0) - { - outtoc.tracks[trknum].trktype = CD_TRACK_AUDIO; - outtoc.tracks[trknum].frames = wavlen/2352; - outinfo.track[trknum].offset = wavoffs; - wavoffs = wavlen = 0; - } - else - { - outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; - outtoc.tracks[trknum].datasize = 0; - outinfo.track[trknum].offset = 0; - } - outtoc.tracks[trknum].subtype = CD_SUB_NONE; - outtoc.tracks[trknum].subsize = 0; - outtoc.tracks[trknum].pgsub = CD_SUB_NONE; - outtoc.tracks[trknum].pregap = 0; - outtoc.tracks[trknum].padframes = 0; - outtoc.tracks[trknum].multicuearea = current_area; - outinfo.track[trknum].idx0offs = -1; - outinfo.track[trknum].idx1offs = 0; - - outinfo.track[trknum].fname.assign(lastfname); // default filename to the last one - - if (EXTRA_VERBOSE) - printf("trk %d: fname %s offset %d area %d\n", trknum, outinfo.track[trknum].fname.c_str(), outinfo.track[trknum].offset, outtoc.tracks[trknum].multicuearea); - - convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); - if (outtoc.tracks[trknum].datasize == 0) - { - fclose(infile); - printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return chd_file::error::UNSUPPORTED_FORMAT; - } + convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]); + } + else if (!strcmp(token, "INDEX")) + { + int idx, frames; - /* next (optional) token on the line is the subcode type */ - TOKENIZE + /* get index number */ + TOKENIZE + idx = strtoul(token, nullptr, 10); - convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]); - } - else if (!strcmp(token, "INDEX")) /* only in bin/cue files */ - { - int idx, frames; + /* get index */ + TOKENIZE + frames = msf_to_frames(token); - /* get index number */ - TOKENIZE - idx = strtoul(token, nullptr, 10); + if (idx < 0 || idx > MAX_INDEX) + { + osd_printf_error("ERROR: encountered invalid index %d\n", idx); + return chd_file::error::INVALID_DATA; + } - /* get index */ - TOKENIZE - frames = msf_to_frames( token ); + outinfo.track[trknum].idx[idx] = frames; - if (idx == 0) + if (idx == 1) + { + if (outtoc.tracks[trknum].pregap == 0 && outinfo.track[trknum].idx[0] != -1) { - outinfo.track[trknum].idx0offs = frames; + outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx[0]; + outtoc.tracks[trknum].pgtype = outtoc.tracks[trknum].trktype; + outtoc.tracks[trknum].pgdatasize = outtoc.tracks[trknum].datasize; } - else if (idx == 1) + else if (outinfo.track[trknum].idx[0] == -1) /* pregap sectors not in file, but we're always using idx 0 for track length calc now */ { - outinfo.track[trknum].idx1offs = frames; - if ((outtoc.tracks[trknum].pregap == 0) && (outinfo.track[trknum].idx0offs != -1)) - { - outtoc.tracks[trknum].pregap = frames - outinfo.track[trknum].idx0offs; - outtoc.tracks[trknum].pgtype = outtoc.tracks[trknum].trktype; - switch (outtoc.tracks[trknum].pgtype) - { - case CD_TRACK_MODE1: - case CD_TRACK_MODE2_FORM1: - outtoc.tracks[trknum].pgdatasize = 2048; - break; - - case CD_TRACK_MODE1_RAW: - case CD_TRACK_MODE2_RAW: - case CD_TRACK_AUDIO: - outtoc.tracks[trknum].pgdatasize = 2352; - break; - - case CD_TRACK_MODE2: - case CD_TRACK_MODE2_FORM_MIX: - outtoc.tracks[trknum].pgdatasize = 2336; - break; - - case CD_TRACK_MODE2_FORM2: - outtoc.tracks[trknum].pgdatasize = 2324; - break; - } - } - else // pregap sectors not in file, but we're always using idx0ofs for track length calc now - { - outinfo.track[trknum].idx0offs = frames; - } + outinfo.track[trknum].idx[0] = frames; } } - else if (!strcmp(token, "PREGAP")) - { - int frames; + } + else if (!strcmp(token, "PREGAP")) + { + int frames; - /* get index */ - TOKENIZE - frames = msf_to_frames( token ); + /* get index */ + TOKENIZE + frames = msf_to_frames(token); - outtoc.tracks[trknum].pregap = frames; - } - else if (!strcmp(token, "POSTGAP")) + outtoc.tracks[trknum].pregap = frames; + } + else if (!strcmp(token, "POSTGAP")) + { + int frames; + + /* get index */ + TOKENIZE + frames = msf_to_frames(token); + + outtoc.tracks[trknum].postgap = frames; + } + else if (!strcmp(token, "FLAGS")) + { + outtoc.tracks[trknum].control_flags = 0; + + /* keep looping over remaining tokens in FLAGS line until there's no more to read */ + while (i < std::size(linebuffer)) { - int frames; + int last_idx = i; - /* get index */ TOKENIZE - frames = msf_to_frames( token ); - outtoc.tracks[trknum].postgap = frames; + if (i == last_idx) + break; + + if (!strcmp(token, "DCP")) + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_DIGITAL_COPY_PERMITTED; + else if (!strcmp(token, "4CH")) + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_4CH; + else if (!strcmp(token, "PRE")) + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_PREEMPHASIS; } } } @@ -2811,164 +2651,255 @@ std::error_condition cdrom_file::parse_gdicue(std::string_view tocfname, toc &ou /* store the number of tracks found */ outtoc.numtrks = trknum + 1; + outtoc.numsessions = sessionnum + 1; /* now go over the files again and set the lengths */ for (trknum = 0; trknum < outtoc.numtrks; trknum++) { uint64_t tlen = 0; - // this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian + if (outinfo.track[trknum].idx[1] == -1) + { + /* index 1 should always be set */ + osd_printf_error("ERROR: track %d is missing INDEX 01 marker\n", trknum+1); + return chd_file::error::INVALID_DATA; + } + + /* this is true for cue/bin and cue/iso, and we need it for cue/wav since .WAV is little-endian */ if (outtoc.tracks[trknum].trktype == CD_TRACK_AUDIO) { outinfo.track[trknum].swap = true; } - // don't do this for .WAV tracks, we already have their length and offset filled out - if (outinfo.track[trknum].offset == 0) + /* don't do this for .WAV tracks, we already have their length and offset filled out */ + if (outinfo.track[trknum].offset != 0) + continue; + + if (trknum+1 >= outtoc.numtrks && trknum > 0 && (outinfo.track[trknum].fname.compare(outinfo.track[trknum-1].fname) == 0)) + { + /* if the last track's filename is the same as the previous track */ + tlen = get_file_size(outinfo.track[trknum].fname); + if (tlen == 0) + { + osd_printf_error("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname); + 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); + } + else if (trknum+1 < outtoc.numtrks && outinfo.track[trknum].fname.compare(outinfo.track[trknum+1].fname) == 0) { - // is this the last track? - if (trknum == (outtoc.numtrks-1)) + /* if the current filename is the same as the next track */ + outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx[0] - outinfo.track[trknum].idx[0]; + + if (outtoc.tracks[trknum].frames == 0) { - /* if we have the same filename as the last track, do it that way */ - if (trknum != 0 && (outinfo.track[trknum].fname.compare(outinfo.track[trknum-1].fname)==0)) + osd_printf_error("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); + return chd_file::error::INVALID_DATA; + } + + if (trknum > 0) + { + const uint32_t previous_track_raw_size = outtoc.tracks[trknum-1].frames * (outtoc.tracks[trknum-1].datasize + outtoc.tracks[trknum-1].subsize); + outinfo.track[trknum].offset = outinfo.track[trknum-1].offset + previous_track_raw_size; + } + } + else if (outtoc.tracks[trknum].frames == 0) + { + /* if the filenames between tracks are different */ + tlen = get_file_size(outinfo.track[trknum].fname); + if (tlen == 0) + { + osd_printf_error("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname); + return std::errc::no_such_file_or_directory; + } + + outtoc.tracks[trknum].frames = tlen / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); + outinfo.track[trknum].offset = 0; + } + + if (outtoc.flags & CD_FLAG_MULTISESSION) + { + if (is_multibin) + { + if (outinfo.track[trknum].leadout == -1 && trknum + 1 < outtoc.numtrks && outtoc.tracks[trknum].session != outtoc.tracks[trknum+1].session) { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) - { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - 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); + /* add a standard lead-out to the last track before changing sessions */ + outinfo.track[trknum].leadout = outtoc.tracks[trknum].session == 0 ? 6750 : 2250; /* first session lead-out (1m30s0f) is longer than the rest (0m30s0f) */ } - else /* data files are different */ + + if (outinfo.track[trknum].leadin == -1 && trknum > 0 && outtoc.tracks[trknum].session != outtoc.tracks[trknum-1].session) { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) - { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum-1].fname.c_str()); - return std::errc::no_such_file_or_directory; - } - tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outtoc.tracks[trknum].frames = tlen; - outinfo.track[trknum].offset = 0; + /* add a standard lead-in to the first track of a new session */ + outinfo.track[trknum].leadin = 4500; /* lead-in (1m0s0f) */ } } else { - /* if we have the same filename as the next track, do it that way */ - if (outinfo.track[trknum].fname.compare(outinfo.track[trknum+1].fname)==0) + if (outinfo.track[trknum].leadout != -1) { - outtoc.tracks[trknum].frames = outinfo.track[trknum+1].idx0offs - outinfo.track[trknum].idx0offs; - - if (trknum == 0) // track 0 offset is 0 + /* + if a lead-out time is specified in a multisession CD then the size of the previous track needs to be trimmed + to use the lead-out time instead of the idx 0 of the next track + */ + const int endframes = outinfo.track[trknum].leadout - outinfo.track[trknum].idx[0]; + if (outtoc.tracks[trknum].frames >= endframes) { - outinfo.track[trknum].offset = 0; - } - else - { - 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 = endframes; /* trim track length */ - if (!outtoc.tracks[trknum].frames) - { - printf("ERROR: unable to determine size of track %d, missing INDEX 01 markers?\n", trknum+1); - return chd_file::error::INVALID_DATA; + if (trknum + 1 < outtoc.numtrks) + { + /* lead-out value becomes just the duration between the lead-out to the pre-gap of the next track */ + outinfo.track[trknum].leadout = outinfo.track[trknum+1].idx[0] - outinfo.track[trknum].leadout; + } } } - else /* data files are different */ + + if (trknum > 0 && outinfo.track[trknum-1].leadout != -1) { - tlen = get_file_size(outinfo.track[trknum].fname); - if (tlen == 0) + /* + ImgBurn bin/cue have dummy data to pad between the lead-out and the start of the next track. + DiscImageCreator img/cue does not have any data between the lead-out and the start of the next track. + + Detecting by extension is an awful way to handle this but there's no other way to determine what format + the data will be in since we don't know the exact length of the last track just from the cue. + */ + if (!core_filename_ends_with(outinfo.track[trknum-1].fname, ".img")) { - printf("ERROR: couldn't find bin file [%s]\n", outinfo.track[trknum].fname.c_str()); - return std::errc::no_such_file_or_directory; + outtoc.tracks[trknum-1].padframes += outinfo.track[trknum-1].leadout; + outtoc.tracks[trknum].frames -= outinfo.track[trknum-1].leadout; + outinfo.track[trknum].offset += outinfo.track[trknum-1].leadout * (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); } - tlen /= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outtoc.tracks[trknum].frames = tlen; - outinfo.track[trknum].offset = 0; } } } } - /* - * Dreamcast patterns are identified by track types and number of tracks - */ - if (outtoc.numtrks > 4 && outtoc.tracks[outtoc.numtrks-1].pgtype == CD_TRACK_MODE1_RAW) + if (is_gdrom) { - if (outtoc.tracks[outtoc.numtrks-2].pgtype == CD_TRACK_AUDIO) - disc_pattern = TYPE_III_SPLIT; - else - disc_pattern = TYPE_III; + /* + * Strip pregaps from Redump tracks and adjust the LBA offset to match TOSEC layout + */ + for (trknum = 1; trknum < outtoc.numtrks; trknum++) + { + uint32_t this_pregap = outtoc.tracks[trknum].pregap; + uint32_t this_offset = this_pregap * (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); + + outtoc.tracks[trknum-1].frames += this_pregap; + outtoc.tracks[trknum-1].splitframes += this_pregap; + + outinfo.track[trknum].offset += this_offset; + outtoc.tracks[trknum].frames -= this_pregap; + outinfo.track[trknum].idx[1] -= this_pregap; + + outtoc.tracks[trknum].pregap = 0; + outtoc.tracks[trknum].pgtype = 0; + } + + /* + * TOC now matches TOSEC layout, set LBA for every track with HIGH-DENSITY area @ LBA 45000 + */ + for (trknum = 1; trknum < outtoc.numtrks; trknum++) + { + if (outtoc.tracks[trknum].multicuearea == HIGH_DENSITY && outtoc.tracks[trknum-1].multicuearea == SINGLE_DENSITY) + { + outtoc.tracks[trknum].physframeofs = 45000; + int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs); + outtoc.tracks[trknum-1].frames += dif; + outtoc.tracks[trknum-1].padframes = dif; + } + else + { + outtoc.tracks[trknum].physframeofs = outtoc.tracks[trknum-1].physframeofs + outtoc.tracks[trknum-1].frames; + } + } } - else if (outtoc.numtrks > 3) + + if (EXTRA_VERBOSE) { - if (outtoc.tracks[outtoc.numtrks-1].pgtype == CD_TRACK_AUDIO) - disc_pattern = TYPE_II; - else - disc_pattern = TYPE_III; + for (trknum = 0; trknum < outtoc.numtrks; trknum++) + { + osd_printf_verbose("session %d trk %d: %d frames @ offset %d, pad=%d, split=%d, area=%d, phys=%d, pregap=%d, pgtype=%d, pgdatasize=%d, idx0=%d, idx1=%d, dataframes=%d\n", + outtoc.tracks[trknum].session + 1, + trknum + 1, + outtoc.tracks[trknum].frames, + outinfo.track[trknum].offset, + outtoc.tracks[trknum].padframes, + outtoc.tracks[trknum].splitframes, + outtoc.tracks[trknum].multicuearea, + outtoc.tracks[trknum].physframeofs, + outtoc.tracks[trknum].pregap, + outtoc.tracks[trknum].pgtype, + outtoc.tracks[trknum].pgdatasize, + outinfo.track[trknum].idx[0], + outinfo.track[trknum].idx[1], + outtoc.tracks[trknum].frames - outtoc.tracks[trknum].padframes); + } } - else if (outtoc.numtrks == 3) + + return std::error_condition(); +} + +/*--------------------------------------------------------------------------------------- + is_gdicue - determine if CUE contains Redump multi-CUE format for Dreamcast GDI +----------------------------------------------------------------------------------------*/ + +/** + * Dreamcast GDI has two images on one disc, SINGLE-DENSITY and HIGH-DENSITY. + * + * Redump stores both images in a single .cue with a REM comment separating the images. + * This multi-cue format replaces the old flawed .gdi format. + * + * http://forum.redump.org/topic/19969/done-sega-dreamcast-multicue-gdi/ + * + * This function looks for strings "REM SINGLE-DENSITY AREA" & "REM HIGH-DENSITY AREA" + * indicating the Redump multi-cue format and therefore a Dreamcast GDI disc. + */ + +bool cdrom_file::is_gdicue(std::string_view tocfname) +{ + char token[512]; + bool has_rem_singledensity = false; + bool has_rem_highdensity = false; + std::string path = std::string(tocfname); + + FILE *infile = fopen(path.c_str(), "rt"); + if (!infile) { - disc_pattern = TYPE_I; + return false; } - /* - * Special handling for TYPE_III_SPLIT, pregap in last track contains 75 frames audio and 150 frames data - */ - if (disc_pattern == TYPE_III_SPLIT) + path = get_file_path(path); + + char linebuffer[512]; + memset(linebuffer, 0, sizeof(linebuffer)); + + while (!feof(infile)) { - assert(outtoc.tracks[outtoc.numtrks-1].pregap == 225); + if (!fgets(linebuffer, 511, infile)) + break; - // grow the AUDIO track into DATA track by 75 frames as per Pattern III - outtoc.tracks[outtoc.numtrks-2].frames += 225; - outtoc.tracks[outtoc.numtrks-2].padframes += 150; - outinfo.track[outtoc.numtrks-2].offset = 150 * (outtoc.tracks[outtoc.numtrks-2].datasize+outtoc.tracks[outtoc.numtrks-2].subsize); - outtoc.tracks[outtoc.numtrks-2].splitframes = 75; + int i = 0; - // skip the pregap when reading the DATA track - outtoc.tracks[outtoc.numtrks-1].frames -= 225; - outinfo.track[outtoc.numtrks-1].offset += 225 * (outtoc.tracks[outtoc.numtrks-1].datasize+outtoc.tracks[outtoc.numtrks-1].subsize); - } + TOKENIZE - /* - * Set LBA for every track with HIGH-DENSITY area @ LBA 45000 - */ - for (trknum = 1; trknum < outtoc.numtrks; trknum++) - { - if (outtoc.tracks[trknum].multicuearea == HIGH_DENSITY && outtoc.tracks[trknum-1].multicuearea == SINGLE_DENSITY) + if (!strcmp(token, "REM")) { - outtoc.tracks[trknum].physframeofs = 45000; - int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs); - outtoc.tracks[trknum-1].frames += dif; - outtoc.tracks[trknum-1].padframes = dif; - } - else - { - outtoc.tracks[trknum].physframeofs = outtoc.tracks[trknum-1].physframeofs + outtoc.tracks[trknum-1].frames; + /* skip to actual data of REM command */ + while (i < std::size(linebuffer) && isspace((uint8_t)linebuffer[i])) + i++; + + if (!strncmp(linebuffer+i, "SINGLE-DENSITY AREA", 19)) + has_rem_singledensity = true; + else if (!strncmp(linebuffer+i, "HIGH-DENSITY AREA", 17)) + has_rem_highdensity = true; } } - if (EXTRA_VERBOSE) - for (trknum = 0; trknum < outtoc.numtrks; trknum++) - { - printf("trk %d: %d frames @ offset %d, pad=%d, split=%d, area=%d, phys=%d, pregap=%d, pgtype=%d, idx0=%d, idx1=%d, (true %d)\n", - trknum+1, - outtoc.tracks[trknum].frames, - outinfo.track[trknum].offset, - outtoc.tracks[trknum].padframes, - outtoc.tracks[trknum].splitframes, - outtoc.tracks[trknum].multicuearea, - outtoc.tracks[trknum].physframeofs, - outtoc.tracks[trknum].pregap, - outtoc.tracks[trknum].pgtype, - outinfo.track[trknum].idx0offs, - outinfo.track[trknum].idx1offs, - outtoc.tracks[trknum].frames - outtoc.tracks[trknum].padframes); - } + fclose(infile); - return std::error_condition(); + return has_rem_singledensity && has_rem_highdensity; } /*------------------------------------------------- @@ -2989,7 +2920,7 @@ std::error_condition cdrom_file::parse_gdicue(std::string_view tocfname, toc &ou std::error_condition cdrom_file::parse_toc(std::string_view tocfname, toc &outtoc, track_input_info &outinfo) { - static char token[512]; + char token[512]; auto pos = tocfname.rfind('.'); std::string tocfext = pos == std::string_view::npos ? std::string() : strmakelower(tocfname.substr(pos + 1)); @@ -3001,10 +2932,7 @@ std::error_condition cdrom_file::parse_toc(std::string_view tocfname, toc &outto if (tocfext == "cue") { - if (is_gdicue(tocfname)) - return parse_gdicue(tocfname, outtoc, outinfo); - else - return parse_cue(tocfname, outtoc, outinfo); + return parse_cue(tocfname, outtoc, outinfo); } if (tocfext == "nrg") @@ -3034,132 +2962,167 @@ std::error_condition cdrom_file::parse_toc(std::string_view tocfname, toc &outto int trknum = -1; char linebuffer[512]; + memset(linebuffer, 0, sizeof(linebuffer)); + while (!feof(infile)) { /* get the next line */ - fgets(linebuffer, 511, infile); + if (!fgets(linebuffer, 511, infile)) + break; - /* if EOF didn't hit, keep going */ - if (!feof(infile)) - { - int i = 0; + int i = 0; + TOKENIZE + + /* + Samples: https://github.com/cdrdao/cdrdao/tree/master/testtocs + + Unimplemented: + CD_TEXT + SILENCE + ZERO + FIFO + PREGAP + CATALOG + ISRC + */ + if (!strcmp(token, "NO")) + { TOKENIZE + if (!strcmp(token, "COPY")) + outtoc.tracks[trknum].control_flags &= ~CD_FLAG_CONTROL_DIGITAL_COPY_PERMITTED; + else if (!strcmp(token, "PRE_EMPHASIS")) + outtoc.tracks[trknum].control_flags &= ~CD_FLAG_CONTROL_PREEMPHASIS; + } + else if (!strcmp(token, "COPY")) + { + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_DIGITAL_COPY_PERMITTED; + } + else if (!strcmp(token, "PRE_EMPHASIS")) + { + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_PREEMPHASIS; + } + else if (!strcmp(token, "TWO_CHANNEL_AUDIO")) + { + outtoc.tracks[trknum].control_flags &= ~CD_FLAG_CONTROL_4CH; + } + else if (!strcmp(token, "FOUR_CHANNEL_AUDIO")) + { + outtoc.tracks[trknum].control_flags |= CD_FLAG_CONTROL_4CH; + } + else if ((!strcmp(token, "DATAFILE")) || (!strcmp(token, "AUDIOFILE")) || (!strcmp(token, "FILE"))) + { + int f; - if ((!strcmp(token, "DATAFILE")) || (!strcmp(token, "AUDIOFILE")) || (!strcmp(token, "FILE"))) - { - int f; + /* found the data file for a track */ + TOKENIZE - /* found the data file for a track */ - TOKENIZE + /* keep the filename */ + outinfo.track[trknum].fname.assign(path).append(token); - /* keep the filename */ - outinfo.track[trknum].fname.assign(path).append(token); + /* get either the offset or the length */ + TOKENIZE - /* get either the offset or the length */ + if (!strcmp(token, "SWAP")) + { TOKENIZE - if (!strcmp(token, "SWAP")) - { - TOKENIZE + outinfo.track[trknum].swap = true; + } + else + { + outinfo.track[trknum].swap = false; + } - outinfo.track[trknum].swap = true; - } - else - { - outinfo.track[trknum].swap = false; - } + if (token[0] == '#') + { + /* it's a decimal offset, use it */ + f = strtoul(&token[1], nullptr, 10); + } + else if (isdigit((uint8_t)token[0])) + { + /* convert the time to an offset */ + f = msf_to_frames(token); - if (token[0] == '#') - { - /* it's a decimal offset, use it */ - f = strtoul(&token[1], nullptr, 10); - } - else if (isdigit((uint8_t)token[0])) - { - /* convert the time to an offset */ - f = msf_to_frames( token ); + f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); + } + else + { + f = 0; + } - f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - } - else - { - f = 0; - } + outinfo.track[trknum].offset = f; - outinfo.track[trknum].offset = f; + TOKENIZE + + if (isdigit((uint8_t)token[0])) + { + // this could be the length or an offset from the previous field. + f = msf_to_frames(token); TOKENIZE if (isdigit((uint8_t)token[0])) { - // this could be the length or an offset from the previous field. - f = msf_to_frames( token ); - - TOKENIZE - - if (isdigit((uint8_t)token[0])) - { - // it was an offset. - f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); + // it was an offset. + f *= (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outinfo.track[trknum].offset += f; + outinfo.track[trknum].offset += f; - // this is the length. - f = msf_to_frames( token ); - } - } - else if( trknum == 0 && outinfo.track[trknum].offset != 0 ) - { - /* the 1st track might have a length with no offset */ - f = outinfo.track[trknum].offset / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); - outinfo.track[trknum].offset = 0; + // this is the length. + f = msf_to_frames(token); } - else - { - /* guesstimate the track length? */ - f = 0; - } - - outtoc.tracks[trknum].frames = f; } - else if (!strcmp(token, "TRACK")) + else if (trknum == 0 && outinfo.track[trknum].offset != 0) { - trknum++; - - /* next token on the line is the track type */ - TOKENIZE + /* the 1st track might have a length with no offset */ + f = outinfo.track[trknum].offset / (outtoc.tracks[trknum].datasize + outtoc.tracks[trknum].subsize); + outinfo.track[trknum].offset = 0; + } + else + { + /* guesstimate the track length? */ + f = 0; + } - outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; - outtoc.tracks[trknum].datasize = 0; - outtoc.tracks[trknum].subtype = CD_SUB_NONE; - outtoc.tracks[trknum].subsize = 0; - outtoc.tracks[trknum].pgsub = CD_SUB_NONE; - outtoc.tracks[trknum].padframes = 0; + outtoc.tracks[trknum].frames = f; + } + else if (!strcmp(token, "TRACK")) + { + trknum++; - convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); - if (outtoc.tracks[trknum].datasize == 0) - { - fclose(infile); - printf("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); - return chd_file::error::UNSUPPORTED_FORMAT; - } + /* next token on the line is the track type */ + TOKENIZE - /* next (optional) token on the line is the subcode type */ - TOKENIZE + outtoc.tracks[trknum].trktype = CD_TRACK_MODE1; + outtoc.tracks[trknum].datasize = 0; + outtoc.tracks[trknum].subtype = CD_SUB_NONE; + outtoc.tracks[trknum].subsize = 0; + outtoc.tracks[trknum].pgsub = CD_SUB_NONE; + outtoc.tracks[trknum].padframes = 0; - convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]); - } - else if (!strcmp(token, "START")) + convert_type_string_to_track_info(token, &outtoc.tracks[trknum]); + if (outtoc.tracks[trknum].datasize == 0) { - int frames; + fclose(infile); + osd_printf_error("ERROR: Unknown track type [%s]. Contact MAMEDEV.\n", token); + return chd_file::error::UNSUPPORTED_FORMAT; + } - /* get index */ - TOKENIZE - frames = msf_to_frames( token ); + /* next (optional) token on the line is the subcode type */ + TOKENIZE - outtoc.tracks[trknum].pregap = frames; - } + convert_subtype_string_to_track_info(token, &outtoc.tracks[trknum]); + } + else if (!strcmp(token, "START")) + { + int frames; + + /* get index */ + TOKENIZE + frames = msf_to_frames(token); + + outtoc.tracks[trknum].pregap = frames; } } @@ -3168,6 +3131,7 @@ std::error_condition cdrom_file::parse_toc(std::string_view tocfname, toc &outto /* store the number of tracks found */ outtoc.numtrks = trknum + 1; + outtoc.numsessions = 1; return std::error_condition(); } diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h index 214a7ed39d6..b11ecb5b3ba 100644 --- a/src/lib/util/cdrom.h +++ b/src/lib/util/cdrom.h @@ -16,6 +16,12 @@ #include "ioprocs.h" #include "osdcore.h" +#include <algorithm> +#include <string> +#include <string_view> +#include <system_error> + + class cdrom_file { public: // tracks are padded to a multiple of this many frames @@ -24,6 +30,7 @@ public: static constexpr uint32_t MAX_TRACKS = 99; /* AFAIK the theoretical limit */ static constexpr uint32_t MAX_SECTOR_DATA = 2352; static constexpr uint32_t MAX_SUBCODE_DATA = 96; + static constexpr uint32_t MAX_INDEX = 99; static constexpr uint32_t FRAME_SIZE = MAX_SECTOR_DATA + MAX_SUBCODE_DATA; static constexpr uint32_t FRAMES_PER_HUNK = 8; @@ -53,29 +60,47 @@ public: enum { - CD_FLAG_GDROM = 0x00000001, // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata - CD_FLAG_GDROMLE = 0x00000002 // legacy GD-ROM, with little-endian CDDA data + CD_FLAG_GDROM = 0x00000001, // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata + CD_FLAG_GDROMLE = 0x00000002, // legacy GD-ROM, with little-endian CDDA data + CD_FLAG_MULTISESSION = 0x00000004, // multisession CD-ROM + }; + + enum + { + CD_FLAG_CONTROL_PREEMPHASIS = 1, + CD_FLAG_CONTROL_DIGITAL_COPY_PERMITTED = 2, + CD_FLAG_CONTROL_DATA_TRACK = 4, + CD_FLAG_CONTROL_4CH = 8, + }; + + enum + { + CD_FLAG_ADR_START_TIME = 1, + CD_FLAG_ADR_CATALOG_CODE, + CD_FLAG_ADR_ISRC_CODE, }; struct track_info { /* fields used by CHDMAN and in MAME */ - uint32_t trktype; /* track type */ - uint32_t subtype; /* subcode data type */ - uint32_t datasize; /* size of data in each sector of this track */ - uint32_t subsize; /* size of subchannel data in each sector of this track */ - uint32_t frames; /* number of frames in this track */ - uint32_t extraframes; /* number of "spillage" frames in this track */ - uint32_t pregap; /* number of pregap frames */ - uint32_t postgap; /* number of postgap frames */ - uint32_t pgtype; /* type of sectors in pregap */ - uint32_t pgsub; /* type of subchannel data in pregap */ - uint32_t pgdatasize; /* size of data in each sector of the pregap */ - uint32_t pgsubsize; /* size of subchannel data in each sector of the pregap */ + uint32_t trktype; /* track type */ + uint32_t subtype; /* subcode data type */ + uint32_t datasize; /* size of data in each sector of this track */ + uint32_t subsize; /* size of subchannel data in each sector of this track */ + uint32_t frames; /* number of frames in this track */ + uint32_t extraframes; /* number of "spillage" frames in this track */ + uint32_t pregap; /* number of pregap frames */ + uint32_t postgap; /* number of postgap frames */ + uint32_t pgtype; /* type of sectors in pregap */ + uint32_t pgsub; /* type of subchannel data in pregap */ + uint32_t pgdatasize; /* size of data in each sector of the pregap */ + uint32_t pgsubsize; /* size of subchannel data in each sector of the pregap */ + uint32_t control_flags; /* metadata flags associated with each track */ + uint32_t session; /* session number */ /* fields used in CHDMAN only */ uint32_t padframes; /* number of frames of padding to add to the end of the track; needed for GDI */ - uint32_t splitframes; /* number of frames to read from the next file; needed for Redump split-bin GDI */ + uint32_t splitframes; /* number of frames from the next file to add to the end of the current track after padding; needed for Redump split-bin GDI */ /* fields used in MAME/MESS only */ uint32_t logframeofs; /* logical frame of actual track data - offset by pregap size if pregap not physically present */ @@ -91,20 +116,21 @@ public: struct toc { uint32_t numtrks; /* number of tracks */ + uint32_t numsessions; /* number of sessions */ uint32_t flags; /* see FLAG_ above */ - track_info tracks[MAX_TRACKS]; + track_info tracks[MAX_TRACKS + 1]; }; struct track_input_entry { track_input_entry() { reset(); } - void reset() { fname.clear(); offset = idx0offs = idx1offs = 0; swap = false; } + void reset() { fname.clear(); offset = 0; leadin = leadout = -1; swap = false; std::fill(std::begin(idx), std::end(idx), -1); } std::string fname; // filename for each track uint32_t offset; // offset in the data file for each track bool swap; // data needs to be byte swapped - uint32_t idx0offs; - uint32_t idx1offs; + int32_t idx[MAX_INDEX + 1]; + int32_t leadin, leadout; // TODO: these should probably be their own tracks entirely }; struct track_input_info @@ -128,6 +154,7 @@ public: uint32_t get_track(uint32_t frame) const; uint32_t get_track_start(uint32_t track) const {return cdtoc.tracks[track == 0xaa ? cdtoc.numtrks : track].logframeofs; } uint32_t get_track_start_phys(uint32_t track) const { return cdtoc.tracks[track == 0xaa ? cdtoc.numtrks : track].physframeofs; } + uint32_t get_track_index(uint32_t frame) const; /* TOC utilities */ static std::error_condition parse_nero(std::string_view tocfname, toc &outtoc, track_input_info &outinfo); @@ -135,10 +162,18 @@ public: static std::error_condition parse_gdi(std::string_view tocfname, toc &outtoc, track_input_info &outinfo); static std::error_condition parse_cue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo); static bool is_gdicue(std::string_view tocfname); - static std::error_condition parse_gdicue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo); static std::error_condition parse_toc(std::string_view tocfname, toc &outtoc, track_input_info &outinfo); + int get_last_session() const { return cdtoc.numsessions ? cdtoc.numsessions : 1; } int get_last_track() const { return cdtoc.numtrks; } - int get_adr_control(int track) const { return track == 0xaa || cdtoc.tracks[track].trktype == CD_TRACK_AUDIO ? 0x10 : 0x14; } + int get_adr_control(int track) const + { + if (track == 0xaa) + track = get_last_track() - 1; // use last track's flags + int adrctl = (CD_FLAG_ADR_START_TIME << 4) | (cdtoc.tracks[track].control_flags & 0x0f); + if (cdtoc.tracks[track].trktype != CD_TRACK_AUDIO) + adrctl |= CD_FLAG_CONTROL_DATA_TRACK; + return adrctl; + } int get_track_type(int track) const { return cdtoc.tracks[track].trktype; } const toc &get_toc() const { return cdtoc; } @@ -254,8 +289,8 @@ private: static std::string get_file_path(std::string &path); static uint64_t get_file_size(std::string_view filename); - static int tokenize( const char *linebuffer, int i, int linebuffersize, char *token, int tokensize ); - static int msf_to_frames( char *token ); + static int tokenize(const char *linebuffer, int i, int linebuffersize, char *token, int tokensize); + static int msf_to_frames(const char *token); static uint32_t parse_wav_sample(std::string_view filename, uint32_t *dataoffs); static uint16_t read_uint16(FILE *infile); static uint32_t read_uint32(FILE *infile); diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp index 194884bfd9a..c05977a84eb 100644 --- a/src/lib/util/chd.cpp +++ b/src/lib/util/chd.cpp @@ -2,8 +2,6 @@ // copyright-holders:Aaron Giles /*************************************************************************** - chd.c - MAME Compressed Hunks of Data file format ***************************************************************************/ @@ -22,11 +20,13 @@ #include <zlib.h> +#include <algorithm> #include <cassert> #include <cstddef> #include <cstdlib> #include <ctime> #include <new> +#include <tuple> //************************************************************************** @@ -134,7 +134,7 @@ struct chd_file::metadata_hash // stream in bigendian order //------------------------------------------------- -inline util::sha1_t chd_file::be_read_sha1(const uint8_t *base)const +inline util::sha1_t chd_file::be_read_sha1(const uint8_t *base) const noexcept { util::sha1_t result; memcpy(&result.m_raw[0], base, sizeof(result.m_raw)); @@ -147,7 +147,7 @@ inline util::sha1_t chd_file::be_read_sha1(const uint8_t *base)const // stream in bigendian order //------------------------------------------------- -inline void chd_file::be_write_sha1(uint8_t *base, util::sha1_t value) +inline void chd_file::be_write_sha1(uint8_t *base, util::sha1_t value) noexcept { memcpy(base, &value.m_raw[0], sizeof(value.m_raw)); } @@ -155,45 +155,45 @@ inline void chd_file::be_write_sha1(uint8_t *base, util::sha1_t value) //------------------------------------------------- // file_read - read from the file at the given -// offset; on failure throw an error +// offset. //------------------------------------------------- -inline void chd_file::file_read(uint64_t offset, void *dest, uint32_t length) const +inline std::error_condition chd_file::file_read(uint64_t offset, void *dest, uint32_t length) const noexcept { // no file = failure - if (!m_file) - throw std::error_condition(error::NOT_OPEN); + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); // seek and read - m_file->seek(offset, SEEK_SET); + std::error_condition err; + err = m_file->seek(offset, SEEK_SET); + if (UNEXPECTED(err)) + return err; 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) + std::tie(err, count) = read(*m_file, dest, length); + if (UNEXPECTED(!err && (count != length))) + return std::error_condition(std::errc::io_error); // TODO: revisit this error code (happens if file is truncated) + return err; } //------------------------------------------------- // file_write - write to the file at the given -// offset; on failure throw an error +// offset. //------------------------------------------------- -inline void chd_file::file_write(uint64_t offset, const void *source, uint32_t length) +inline std::error_condition chd_file::file_write(uint64_t offset, const void *source, uint32_t length) noexcept { // no file = failure - if (!m_file) - throw std::error_condition(error::NOT_OPEN); + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); // seek and write - m_file->seek(offset, SEEK_SET); - 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 + std::error_condition err; + err = m_file->seek(offset, SEEK_SET); + if (UNEXPECTED(err)) + return err; + return write(*m_file, source, length).first; } @@ -205,21 +205,20 @@ 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) + if (UNEXPECTED(!m_file)) throw std::error_condition(error::NOT_OPEN); // seek to the end and align if necessary + std::error_condition err; err = m_file->seek(0, SEEK_END); - if (err) + if (UNEXPECTED(err)) throw err; if (alignment != 0) { uint64_t offset; err = m_file->tell(offset); - if (err) + if (UNEXPECTED(err)) throw err; uint32_t delta = offset % alignment; if (delta != 0) @@ -232,8 +231,8 @@ inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint3 { 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) + std::tie(err, count) = write(*m_file, buffer, bytes_to_write); + if (UNEXPECTED(err)) throw err; delta -= count; } @@ -243,14 +242,11 @@ inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint3 // write the real data uint64_t offset; err = m_file->tell(offset); - if (err) + if (UNEXPECTED(err)) throw err; - size_t count; - err = m_file->write(source, length, count); - if (err) + std::tie(err, std::ignore) = write(*m_file, source, length); + if (UNEXPECTED(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; } @@ -260,11 +256,14 @@ inline uint64_t chd_file::file_append(const void *source, uint32_t length, uint3 // necessary to represent all numbers 0..value //------------------------------------------------- -inline uint8_t chd_file::bits_for_value(uint64_t value) +inline uint8_t chd_file::bits_for_value(uint64_t value) noexcept { uint8_t result = 0; while (value != 0) - value >>= 1, result++; + { + value >>= 1; + result++; + } return result; } @@ -338,20 +337,14 @@ bool chd_file::parent_missing() const noexcept * @return A sha1_t. */ -util::sha1_t chd_file::sha1() +util::sha1_t chd_file::sha1() const noexcept { - try - { - // read the big-endian version - uint8_t rawbuf[sizeof(util::sha1_t)]; - file_read(m_sha1_offset, rawbuf, sizeof(rawbuf)); - return be_read_sha1(rawbuf); - } - catch (std::error_condition const &) - { - // on failure, return nullptr - return util::sha1_t::null; - } + // read the big-endian version + uint8_t rawbuf[sizeof(util::sha1_t)]; + std::error_condition err = file_read(m_sha1_offset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(err)) + return util::sha1_t::null; // on failure, return null + return be_read_sha1(rawbuf); } /** @@ -367,22 +360,24 @@ util::sha1_t chd_file::sha1() * @return A sha1_t. */ -util::sha1_t chd_file::raw_sha1() +util::sha1_t chd_file::raw_sha1() const noexcept { try { // determine offset within the file for data-only - if (!m_rawsha1_offset) + if (UNEXPECTED(!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)); + std::error_condition err = file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(err)) + throw err; return be_read_sha1(rawbuf); } catch (std::error_condition const &) { - // on failure, return nullptr + // on failure, return null return util::sha1_t::null; } } @@ -400,17 +395,19 @@ util::sha1_t chd_file::raw_sha1() * @return A sha1_t. */ -util::sha1_t chd_file::parent_sha1() +util::sha1_t chd_file::parent_sha1() const noexcept { try { // determine offset within the file - if (!m_parentsha1_offset) + if (UNEXPECTED(!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)); + std::error_condition err = file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(err)) + throw err; return be_read_sha1(rawbuf); } catch (std::error_condition const &) @@ -441,49 +438,51 @@ std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compr return std::error_condition(error::HUNK_OUT_OF_RANGE); // get the map pointer - uint8_t *rawmap; switch (m_version) { - // v3/v4 map entries - case 3: - case 4: - rawmap = &m_rawmap[16 * hunknum]; + // v3/v4 map entries + case 3: + case 4: + { + uint8_t const *const rawmap = &m_rawmap[16 * hunknum]; switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK) { - case V34_MAP_ENTRY_TYPE_COMPRESSED: - compressor = CHD_CODEC_ZLIB; - compbytes = get_u16be(&rawmap[12]) + (rawmap[14] << 16); - break; + case V34_MAP_ENTRY_TYPE_COMPRESSED: + compressor = CHD_CODEC_ZLIB; + compbytes = get_u16be(&rawmap[12]) + (rawmap[14] << 16); + break; - case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: - compressor = CHD_CODEC_NONE; - compbytes = m_hunkbytes; - break; + case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: + compressor = CHD_CODEC_NONE; + compbytes = m_hunkbytes; + break; - case V34_MAP_ENTRY_TYPE_MINI: - compressor = CHD_CODEC_MINI; - compbytes = 0; - break; + case V34_MAP_ENTRY_TYPE_MINI: + compressor = CHD_CODEC_MINI; + compbytes = 0; + break; - case V34_MAP_ENTRY_TYPE_SELF_HUNK: - compressor = CHD_CODEC_SELF; - compbytes = 0; - break; + case V34_MAP_ENTRY_TYPE_SELF_HUNK: + compressor = CHD_CODEC_SELF; + compbytes = 0; + break; - case V34_MAP_ENTRY_TYPE_PARENT_HUNK: - compressor = CHD_CODEC_PARENT; - compbytes = 0; - break; + case V34_MAP_ENTRY_TYPE_PARENT_HUNK: + compressor = CHD_CODEC_PARENT; + compbytes = 0; + break; } - break; + } + break; - // v5 map entries - case 5: - rawmap = &m_rawmap[m_mapentrybytes * hunknum]; + // v5 map entries + case 5: + { + uint8_t const *const rawmap = &m_rawmap[m_mapentrybytes * hunknum]; - // uncompressed case if (!compressed()) { + // uncompressed case if (get_u32be(&rawmap[0]) == 0) { compressor = CHD_CODEC_PARENT; @@ -494,12 +493,12 @@ std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compr compressor = CHD_CODEC_NONE; compbytes = m_hunkbytes; } - break; } - - // compressed case - switch (rawmap[0]) + else { + // compressed case + switch (rawmap[0]) + { case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: @@ -525,9 +524,12 @@ std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compr default: return error::UNKNOWN_COMPRESSION; + } } - break; + } + break; } + return std::error_condition(); } @@ -541,20 +543,36 @@ std::error_condition chd_file::hunk_info(uint32_t hunknum, chd_codec_type &compr * @param rawdata The rawdata. */ -void chd_file::set_raw_sha1(util::sha1_t rawdata) +std::error_condition chd_file::set_raw_sha1(util::sha1_t rawdata) noexcept { + uint64_t const offset = (m_rawsha1_offset != 0) ? m_rawsha1_offset : m_sha1_offset; + assert(offset != 0); + // create a big-endian version uint8_t rawbuf[sizeof(util::sha1_t)]; be_write_sha1(rawbuf, rawdata); // write to the header - uint64_t offset = (m_rawsha1_offset != 0) ? m_rawsha1_offset : m_sha1_offset; - assert(offset != 0); - file_write(offset, rawbuf, sizeof(rawbuf)); + std::error_condition err = file_write(offset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(err)) + return err; - // if we have a separate rawsha1_offset, update the full sha1 as well - if (m_rawsha1_offset != 0) - metadata_update_hash(); + try + { + // if we have a separate rawsha1_offset, update the full sha1 as well + if (m_rawsha1_offset != 0) + metadata_update_hash(); + } + catch (std::error_condition const &err) + { + return err; + } + catch (std::bad_alloc const &) + { + return std::errc::not_enough_memory; + } + + return std::error_condition(); } /** @@ -569,23 +587,24 @@ void chd_file::set_raw_sha1(util::sha1_t rawdata) * @param parent The parent. */ -void chd_file::set_parent_sha1(util::sha1_t parent) +std::error_condition chd_file::set_parent_sha1(util::sha1_t parent) noexcept { // if no file, fail - if (!m_file) - throw std::error_condition(error::INVALID_FILE); + if (UNEXPECTED(!m_file)) + return std::error_condition(error::INVALID_FILE); + + assert(m_parentsha1_offset != 0); // create a big-endian version uint8_t rawbuf[sizeof(util::sha1_t)]; be_write_sha1(rawbuf, parent); // write to the header - assert(m_parentsha1_offset != 0); - file_write(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); + return file_write(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); } /** - * @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]) + * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, const chd_codec_type (&compression)[4]) * * @brief ------------------------------------------------- * create - create a new file with no parent using an existing opened file handle @@ -605,12 +624,12 @@ std::error_condition chd_file::create( uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, - chd_codec_type compression[4]) + const chd_codec_type (&compression)[4]) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(m_file)) return error::ALREADY_OPEN; - else if (!file) + else if (UNEXPECTED(!file)) return std::errc::invalid_argument; // set the header parameters @@ -626,7 +645,7 @@ std::error_condition chd_file::create( } /** - * @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) + * @fn std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, const chd_codec_type (&compression)[4], chd_file &parent) * * @brief ------------------------------------------------- * create - create a new file with a parent using an existing opened file handle @@ -645,13 +664,13 @@ std::error_condition chd_file::create( util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, - chd_codec_type compression[4], + const chd_codec_type (&compression)[4], chd_file &parent) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(m_file)) return error::ALREADY_OPEN; - else if (!file) + else if (UNEXPECTED(!file)) return std::errc::invalid_argument; // set the header parameters @@ -667,7 +686,7 @@ std::error_condition chd_file::create( } /** - * @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]) + * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, const chd_codec_type (&compression)[4]) * * @brief ------------------------------------------------- * create - create a new file with no parent using a filename @@ -687,23 +706,23 @@ std::error_condition chd_file::create( uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, - chd_codec_type compression[4]) + const chd_codec_type (&compression)[4]) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(m_file)) return error::ALREADY_OPEN; // create the new file util::core_file::ptr file; std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr) + if (UNEXPECTED(filerr)) return filerr; // create the file normally, then claim the file std::error_condition chderr = create(std::move(file), logicalbytes, hunkbytes, unitbytes, compression); // if an error happened, close and delete the file - if (chderr) + if (UNEXPECTED(chderr)) { file.reset(); osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view @@ -712,7 +731,7 @@ std::error_condition chd_file::create( } /** - * @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) + * @fn std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, const chd_codec_type (&compression)[4], chd_file &parent) * * @brief ------------------------------------------------- * create - create a new file with a parent using a filename @@ -731,24 +750,24 @@ std::error_condition chd_file::create( std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, - chd_codec_type compression[4], + const chd_codec_type (&compression)[4], chd_file &parent) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(m_file)) return error::ALREADY_OPEN; // create the new file util::core_file::ptr file; std::error_condition filerr = util::core_file::open(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, file); - if (filerr) + if (UNEXPECTED(filerr)) return filerr; // create the file normally, then claim the file std::error_condition chderr = create(std::move(file), logicalbytes, hunkbytes, compression, parent); // if an error happened, close and delete the file - if (chderr) + if (UNEXPECTED(chderr)) { file.reset(); osd_file::remove(std::string(filename)); // FIXME: allow osd_file to use std::string_view @@ -777,14 +796,14 @@ std::error_condition chd_file::open( const open_parent_func &open_parent) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(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; std::error_condition filerr = util::core_file::open(filename, openflags, file); - if (filerr) + if (UNEXPECTED(filerr)) return filerr; // now open the CHD @@ -812,9 +831,9 @@ std::error_condition chd_file::open( const open_parent_func &open_parent) { // make sure we don't already have a file open - if (m_file) + if (UNEXPECTED(m_file)) return error::ALREADY_OPEN; - else if (!file) + else if (UNEXPECTED(!file)) return std::errc::invalid_argument; // open the file @@ -848,7 +867,7 @@ void chd_file::close() m_hunkcount = 0; m_unitbytes = 0; m_unitcount = 0; - memset(m_compression, 0, sizeof(m_compression)); + std::fill(std::begin(m_compression), std::end(m_compression), 0); m_parent.reset(); m_parent_missing = false; @@ -873,6 +892,105 @@ void chd_file::close() m_cachehunk = ~0; } +std::error_condition chd_file::codec_process_hunk(uint32_t hunknum) +{ + // punt if no file + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); + + // return an error if out of range + if (UNEXPECTED(hunknum >= m_hunkcount)) + return std::error_condition(error::HUNK_OUT_OF_RANGE); + + // wrap this for clean reporting + try + { + // get a pointer to the map entry + switch (m_version) + { + // v3/v4 map entries + case 3: + case 4: + { + uint8_t const *const rawmap = &m_rawmap[16 * hunknum]; + uint64_t const blockoffs = get_u64be(&rawmap[0]); + switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK) + { + case V34_MAP_ENTRY_TYPE_COMPRESSED: + { + uint32_t const blocklen = get_u16be(&rawmap[12]) | (uint32_t(rawmap[14]) << 16); + std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen); + if (UNEXPECTED(err)) + return err; + m_decompressor[0]->process(&m_compressed[0], blocklen); + return std::error_condition(); + } + + case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: + case V34_MAP_ENTRY_TYPE_MINI: + return std::error_condition(error::UNSUPPORTED_FORMAT); + + case V34_MAP_ENTRY_TYPE_SELF_HUNK: + return codec_process_hunk(blockoffs); + + case V34_MAP_ENTRY_TYPE_PARENT_HUNK: + if (UNEXPECTED(m_parent_missing)) + return std::error_condition(error::REQUIRES_PARENT); + return m_parent->codec_process_hunk(blockoffs); + } + } + break; + + // v5 map entries + case 5: + { + if (UNEXPECTED(!compressed())) + return std::error_condition(error::UNSUPPORTED_FORMAT); + + // compressed case + uint8_t const *const rawmap = &m_rawmap[m_mapentrybytes * hunknum]; + uint32_t const blocklen = get_u24be(&rawmap[1]); + uint64_t const blockoffs = get_u48be(&rawmap[4]); + switch (rawmap[0]) + { + case COMPRESSION_TYPE_0: + case COMPRESSION_TYPE_1: + case COMPRESSION_TYPE_2: + case COMPRESSION_TYPE_3: + { + std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen); + if (UNEXPECTED(err)) + return err; + auto &decompressor = *m_decompressor[rawmap[0]]; + decompressor.process(&m_compressed[0], blocklen); + return std::error_condition(); + } + + case COMPRESSION_NONE: + return std::error_condition(error::UNSUPPORTED_FORMAT); + + case COMPRESSION_SELF: + return codec_process_hunk(blockoffs); + + case COMPRESSION_PARENT: + if (UNEXPECTED(m_parent_missing)) + return std::error_condition(error::REQUIRES_PARENT); + return m_parent->codec_process_hunk(blockoffs / (m_parent->hunk_bytes() / m_parent->unit_bytes())); + } + break; + } + } + + // if we get here, the map contained an unsupported block type + return std::error_condition(error::INVALID_DATA); + } + catch (std::error_condition const &err) + { + // just return errors + return err; + } +} + /** * @fn std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer) * @@ -893,126 +1011,148 @@ void chd_file::close() * @param hunknum The hunknum. * @param [in,out] buffer If non-null, the buffer. * - * @return The hunk. + * @return An error condition. */ std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer) { + // punt if no file + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); + + // return an error if out of range + if (UNEXPECTED(hunknum >= m_hunkcount)) + return std::error_condition(error::HUNK_OUT_OF_RANGE); + + auto *const dest = reinterpret_cast<uint8_t *>(buffer); + // wrap this for clean reporting try { - // punt if no file - if (!m_file) - throw std::error_condition(error::NOT_OPEN); - - // return an error if out of range - if (hunknum >= m_hunkcount) - throw std::error_condition(error::HUNK_OUT_OF_RANGE); - // get a pointer to the map entry - uint64_t blockoffs; - uint32_t blocklen; - util::crc32_t blockcrc; - uint8_t *rawmap; - auto *dest = reinterpret_cast<uint8_t *>(buffer); switch (m_version) { - // v3/v4 map entries - case 3: - case 4: - rawmap = &m_rawmap[16 * hunknum]; - blockoffs = get_u64be(&rawmap[0]); - blockcrc = get_u32be(&rawmap[8]); + // v3/v4 map entries + case 3: + case 4: + { + uint8_t const *const rawmap = &m_rawmap[16 * hunknum]; + uint64_t const blockoffs = get_u64be(&rawmap[0]); + util::crc32_t const blockcrc = get_u32be(&rawmap[8]); + bool const nocrc = rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC; switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK) { - case V34_MAP_ENTRY_TYPE_COMPRESSED: - blocklen = get_u16be(&rawmap[12]) + (rawmap[14] << 16); - file_read(blockoffs, &m_compressed[0], blocklen); + case V34_MAP_ENTRY_TYPE_COMPRESSED: + { + uint32_t const blocklen = get_u16be(&rawmap[12]) | (uint32_t(rawmap[14]) << 16); + std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen); + if (UNEXPECTED(err)) + return err; 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 std::error_condition(error::DECOMPRESSION_ERROR); + if (UNEXPECTED(!nocrc && (util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc))) + return 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 std::error_condition(error::DECOMPRESSION_ERROR); + case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: + { + std::error_condition err = file_read(blockoffs, dest, m_hunkbytes); + if (UNEXPECTED(err)) + return err; + if (UNEXPECTED(!nocrc && (util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc))) + return std::error_condition(error::DECOMPRESSION_ERROR); return std::error_condition(); + } - case V34_MAP_ENTRY_TYPE_MINI: - put_u64be(dest, blockoffs); - 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 std::error_condition(error::DECOMPRESSION_ERROR); - return std::error_condition(); + case V34_MAP_ENTRY_TYPE_MINI: + put_u64be(dest, blockoffs); + for (uint32_t bytes = 8; bytes < m_hunkbytes; bytes++) + dest[bytes] = dest[bytes - 8]; + if (UNEXPECTED(!nocrc && (util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc))) + return 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_SELF_HUNK: + return read_hunk(blockoffs, dest); - case V34_MAP_ENTRY_TYPE_PARENT_HUNK: - if (m_parent_missing) - throw std::error_condition(error::REQUIRES_PARENT); - return m_parent->read_hunk(blockoffs, dest); + case V34_MAP_ENTRY_TYPE_PARENT_HUNK: + if (UNEXPECTED(m_parent_missing)) + return std::error_condition(error::REQUIRES_PARENT); + return m_parent->read_hunk(blockoffs, dest); } - break; + } + break; - // v5 map entries - case 5: - rawmap = &m_rawmap[m_mapentrybytes * hunknum]; + // v5 map entries + case 5: + { + uint8_t const *const rawmap = &m_rawmap[m_mapentrybytes * hunknum]; - // uncompressed case if (!compressed()) { - blockoffs = mulu_32x32(get_u32be(rawmap), m_hunkbytes); + // uncompressed case + uint64_t const blockoffs = mulu_32x32(get_u32be(rawmap), m_hunkbytes); if (blockoffs != 0) - file_read(blockoffs, dest, m_hunkbytes); - else if (m_parent_missing) - throw std::error_condition(error::REQUIRES_PARENT); + return file_read(blockoffs, dest, m_hunkbytes); + else if (UNEXPECTED(m_parent_missing)) + return std::error_condition(error::REQUIRES_PARENT); else if (m_parent) - m_parent->read_hunk(hunknum, dest); + return m_parent->read_hunk(hunknum, dest); else memset(dest, 0, m_hunkbytes); return std::error_condition(); } - - // compressed case - blocklen = get_u24be(&rawmap[1]); - blockoffs = get_u48be(&rawmap[4]); - blockcrc = get_u16be(&rawmap[10]); - switch (rawmap[0]) + else { + // compressed case + uint32_t const blocklen = get_u24be(&rawmap[1]); + uint64_t const blockoffs = get_u48be(&rawmap[4]); + util::crc16_t const blockcrc = get_u16be(&rawmap[10]); + switch (rawmap[0]) + { case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: - 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 std::error_condition(error::DECOMPRESSION_ERROR); - if (m_decompressor[rawmap[0]]->lossy() && util::crc16_creator::simple(&m_compressed[0], blocklen) != blockcrc) - throw std::error_condition(error::DECOMPRESSION_ERROR); - return std::error_condition(); + { + std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen); + if (UNEXPECTED(err)) + return err; + auto &decompressor = *m_decompressor[rawmap[0]]; + decompressor.decompress(&m_compressed[0], blocklen, dest, m_hunkbytes); + util::crc16_t const calculated = !decompressor.lossy() + ? util::crc16_creator::simple(dest, m_hunkbytes) + : util::crc16_creator::simple(&m_compressed[0], blocklen); + if (UNEXPECTED(calculated != blockcrc)) + return 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 std::error_condition(error::DECOMPRESSION_ERROR); - return std::error_condition(); + { + std::error_condition err = file_read(blockoffs, dest, m_hunkbytes); + if (UNEXPECTED(err)) + return err; + if (UNEXPECTED(util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc)) + return 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 std::error_condition(error::REQUIRES_PARENT); - return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); + if (UNEXPECTED(m_parent_missing)) + return std::error_condition(error::REQUIRES_PARENT); + return m_parent->read_bytes(blockoffs * m_parent->unit_bytes(), dest, m_hunkbytes); + } } break; + } } - // if we get here, something was wrong - throw std::error_condition(std::errc::io_error); + // if we get here, the map contained an unsupported block type + return std::error_condition(error::INVALID_DATA); } catch (std::error_condition const &err) { @@ -1042,68 +1182,73 @@ std::error_condition chd_file::read_hunk(uint32_t hunknum, 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) - throw std::error_condition(error::NOT_OPEN); + // punt if no file + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); - // return an error if out of range - if (hunknum >= m_hunkcount) - throw std::error_condition(error::HUNK_OUT_OF_RANGE); + // return an error if out of range + if (UNEXPECTED(hunknum >= m_hunkcount)) + return std::error_condition(error::HUNK_OUT_OF_RANGE); - // if not writeable, fail - if (!m_allow_writes) - throw std::error_condition(error::FILE_NOT_WRITEABLE); + // if not writeable, fail + if (UNEXPECTED(!m_allow_writes)) + return std::error_condition(error::FILE_NOT_WRITEABLE); - // uncompressed writes only via this interface - if (compressed()) - throw std::error_condition(error::FILE_NOT_WRITEABLE); + // uncompressed writes only via this interface + if (UNEXPECTED(compressed())) + return 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]; - uint32_t rawentry = get_u32be(rawmap); + // see if we have allocated the space on disk for this hunk + uint8_t *const rawmap = &m_rawmap[hunknum * 4]; + uint32_t rawentry = get_u32be(rawmap); - // if not, allocate one now - if (rawentry == 0) + // if not, allocate one now + if (rawentry == 0) + { + // first make sure we need to allocate it + bool all_zeros = true; + const auto *scan = reinterpret_cast<const uint32_t *>(buffer); + for (uint32_t index = 0; index < m_hunkbytes / 4; index++) { - // first make sure we need to allocate it - bool all_zeros = true; - const auto *scan = reinterpret_cast<const uint32_t *>(buffer); - for (uint32_t index = 0; index < m_hunkbytes / 4; index++) - if (scan[index] != 0) - { - all_zeros = false; - break; - } + if (scan[index] != 0) + { + all_zeros = false; + break; + } + } - // if it's all zeros, do nothing more - if (all_zeros) - return std::error_condition(); + // if it's all zeros, do nothing more + if (all_zeros) + return std::error_condition(); + // wrap this for clean reporting + try + { // append new data to the end of the file, aligning the first chunk rawentry = file_append(buffer, m_hunkbytes, m_hunkbytes) / m_hunkbytes; - - // write the map entry back - put_u32be(rawmap, rawentry); - file_write(m_mapoffset + hunknum * 4, rawmap, 4); - - // update the cached hunk if we just wrote it - if (hunknum == m_cachehunk && buffer != &m_cache[0]) - memcpy(&m_cache[0], buffer, m_hunkbytes); } - else + catch (std::error_condition const &err) { - // otherwise, just overwrite - file_write(uint64_t(rawentry) * uint64_t(m_hunkbytes), buffer, m_hunkbytes); + // just return errors + return err; } + + // write the map entry back + put_u32be(rawmap, rawentry); + std::error_condition err = file_write(m_mapoffset + hunknum * 4, rawmap, 4); + if (UNEXPECTED(err)) + return err; + + // update the cached hunk if we just wrote it + if (hunknum == m_cachehunk && buffer != &m_cache[0]) + memcpy(&m_cache[0], buffer, m_hunkbytes); + return std::error_condition(); } - catch (std::error_condition const &err) + else { - // just return errors - return err; + // otherwise, just overwrite + return file_write(uint64_t(rawentry) * uint64_t(m_hunkbytes), buffer, m_hunkbytes); } } @@ -1163,36 +1308,36 @@ std::error_condition chd_file::write_units(uint64_t unitnum, const void *buffer, 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; - uint32_t last_hunk = (offset + bytes - 1) / m_hunkbytes; + uint32_t const first_hunk = offset / m_hunkbytes; + uint32_t const last_hunk = (offset + bytes - 1) / m_hunkbytes; auto *dest = reinterpret_cast<uint8_t *>(buffer); for (uint32_t curhunk = first_hunk; curhunk <= last_hunk; curhunk++) { // determine start/end boundaries - uint32_t startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; - 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 - std::error_condition err; - if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) - err = read_hunk(curhunk, dest); + uint32_t const startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; + uint32_t const endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); - // otherwise, read from the cache + if ((startoffs == 0) && (endoffs == m_hunkbytes - 1) && (curhunk != m_cachehunk)) + { + // if it's a full block, just read directly from disk unless it's the cached hunk + std::error_condition err = read_hunk(curhunk, dest); + if (UNEXPECTED(err)) + return err; + } else { + // otherwise, read from the cache if (curhunk != m_cachehunk) { - err = read_hunk(curhunk, &m_cache[0]); - if (err) + std::error_condition err = read_hunk(curhunk, &m_cache[0]); + if (UNEXPECTED(err)) return err; m_cachehunk = curhunk; } memcpy(dest, &m_cache[startoffs], endoffs + 1 - startoffs); } - // handle errors and advance - if (err) - return err; + // advance dest += endoffs + 1 - startoffs; } return std::error_condition(); @@ -1216,27 +1361,28 @@ std::error_condition chd_file::read_bytes(uint64_t offset, void *buffer, uint32_ 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; - uint32_t last_hunk = (offset + bytes - 1) / m_hunkbytes; - const auto *source = reinterpret_cast<const uint8_t *>(buffer); + uint32_t const first_hunk = offset / m_hunkbytes; + uint32_t const last_hunk = (offset + bytes - 1) / m_hunkbytes; + auto const *source = reinterpret_cast<uint8_t const *>(buffer); for (uint32_t curhunk = first_hunk; curhunk <= last_hunk; curhunk++) { // determine start/end boundaries - uint32_t startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; - uint32_t endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1); + uint32_t const startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0; + uint32_t const 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 std::error_condition err; - if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk) + if ((startoffs == 0) && (endoffs == m_hunkbytes - 1) && (curhunk != m_cachehunk)) + { + // if it's a full block, just write directly to disk unless it's the cached hunk err = write_hunk(curhunk, source); - - // otherwise, write from the cache + } else { + // otherwise, write from the cache if (curhunk != m_cachehunk) { err = read_hunk(curhunk, &m_cache[0]); - if (err) + if (UNEXPECTED(err)) return err; m_cachehunk = curhunk; } @@ -1245,7 +1391,7 @@ std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, } // handle errors and advance - if (err) + if (UNEXPECTED(err)) return err; source += endoffs + 1 - startoffs; } @@ -1266,29 +1412,20 @@ std::error_condition chd_file::write_bytes(uint64_t offset, const void *buffer, * @param searchindex The searchindex. * @param [in,out] output The output. * - * @return The metadata. + * @return An error condition. */ std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_t searchindex, std::string &output) { - // wrap this for clean reporting - try - { - // if we didn't find it, just return - metadata_entry metaentry; - if (!metadata_find(searchtag, searchindex, metaentry)) - return 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 std::error_condition(); - } - catch (std::error_condition const &err) - { - // just return errors + // if we didn't find it, just return + metadata_entry metaentry; + if (std::error_condition err = metadata_find(searchtag, searchindex, metaentry)) return err; - } + + // read the metadata + try { output.assign(metaentry.length, '\0'); } + catch (std::bad_alloc const &) { return std::errc::not_enough_memory; } + return file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); } /** @@ -1303,29 +1440,20 @@ std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_ * @param searchindex The searchindex. * @param [in,out] output The output. * - * @return The metadata. + * @return An error condition. */ 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 - { - // if we didn't find it, just return - metadata_entry metaentry; - if (!metadata_find(searchtag, searchindex, metaentry)) - 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 std::error_condition(); - } - catch (std::error_condition const &err) - { - // just return errors + // if we didn't find it, just return + metadata_entry metaentry; + if (std::error_condition err = metadata_find(searchtag, searchindex, metaentry)) return err; - } + + // read the metadata + try { output.resize(metaentry.length); } + catch (std::bad_alloc const &) { return std::errc::not_enough_memory; } + return file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); } /** @@ -1342,29 +1470,19 @@ std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_ * @param outputlen The outputlen. * @param [in,out] resultlen The resultlen. * - * @return The metadata. + * @return An error condition. */ 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 - { - // if we didn't find it, just return - metadata_entry metaentry; - if (!metadata_find(searchtag, searchindex, metaentry)) - 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 std::error_condition(); - } - catch (std::error_condition const &err) - { - // just return errors + // if we didn't find it, just return + metadata_entry metaentry; + if (std::error_condition err = metadata_find(searchtag, searchindex, metaentry)) return err; - } + + // read the metadata + resultlen = metaentry.length; + return file_read(metaentry.offset + METADATA_HEADER_SIZE, output, std::min(outputlen, resultlen)); } /** @@ -1381,31 +1499,28 @@ std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_ * @param [in,out] resulttag The resulttag. * @param [in,out] resultflags The resultflags. * - * @return The metadata. + * @return An error condition. */ 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 - { - // if we didn't find it, just return - metadata_entry metaentry; - if (!metadata_find(searchtag, searchindex, metaentry)) - 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 std::error_condition(); - } - catch (std::error_condition const &err) - { - // just return errors + std::error_condition err; + + // if we didn't find it, just return + metadata_entry metaentry; + err = metadata_find(searchtag, searchindex, metaentry); + if (err) return err; - } + + // read the metadata + try { output.resize(metaentry.length); } + catch (std::bad_alloc const &) { return std::errc::not_enough_memory; } + err = file_read(metaentry.offset + METADATA_HEADER_SIZE, &output[0], metaentry.length); + if (UNEXPECTED(err)) + return err; + resulttag = metaentry.metatag; + resultflags = metaentry.flags; + return std::error_condition(); } /** @@ -1426,40 +1541,52 @@ std::error_condition chd_file::read_metadata(chd_metadata_tag searchtag, uint32_ 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 (UNEXPECTED((inputlen < 1) || (inputlen >= 16 * 1024 * 1024))) + return std::error_condition(std::errc::invalid_argument); + + // find the entry if it already exists + metadata_entry metaentry; + bool finished = false; + std::error_condition err = metadata_find(metatag, metaindex, metaentry); + if (!err) { - // must write at least 1 byte and no more than 16MB - if (inputlen < 1 || inputlen >= 16 * 1024 * 1024) - return std::error_condition(std::errc::invalid_argument); - - // find the entry if it already exists - metadata_entry metaentry; - bool finished = false; - if (metadata_find(metatag, metaindex, metaentry)) + if (inputlen <= metaentry.length) { // if the new data fits over the old data, just overwrite - if (inputlen <= metaentry.length) - { - file_write(metaentry.offset + METADATA_HEADER_SIZE, inputbuf, inputlen); - - // if the lengths don't match, we need to update the length in our header - if (inputlen != metaentry.length) - { - uint8_t length[3]; - put_u24be(length, inputlen); - file_write(metaentry.offset + 5, length, sizeof(length)); - } + err = file_write(metaentry.offset + METADATA_HEADER_SIZE, inputbuf, inputlen); + if (UNEXPECTED(err)) + return err; - // indicate we did everything - finished = true; + // if the lengths don't match, we need to update the length in our header + if (inputlen != metaentry.length) + { + uint8_t length[3]; + put_u24be(length, inputlen); + err = file_write(metaentry.offset + 5, length, sizeof(length)); + if (UNEXPECTED(err)) + return err; } + // indicate we did everything + finished = true; + } + else + { // if it doesn't fit, unlink the current entry - else - metadata_set_previous_next(metaentry.prev, metaentry.next); + err = metadata_set_previous_next(metaentry.prev, metaentry.next); + if (UNEXPECTED(err)) + return err; } + } + else if (UNEXPECTED(err != error::METADATA_NOT_FOUND)) + { + return err; + } + // wrap this for clean reporting + try + { // if not yet done, create a new entry and append if (!finished) { @@ -1475,7 +1602,9 @@ std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t file_append(inputbuf, inputlen); // set the previous entry to point to us - metadata_set_previous_next(metaentry.prev, offset); + err = metadata_set_previous_next(metaentry.prev, offset); + if (UNEXPECTED(err)) + return err; } // update the hash @@ -1487,6 +1616,10 @@ std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t // return any errors return err; } + catch (std::bad_alloc const &) + { + return std::errc::not_enough_memory; + } } /** @@ -1507,23 +1640,13 @@ std::error_condition chd_file::write_metadata(chd_metadata_tag metatag, uint32_t std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_t metaindex) { - // wrap this for clean reporting - try - { - // find the entry - metadata_entry metaentry; - if (!metadata_find(metatag, metaindex, metaentry)) - 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 std::error_condition(); - } - catch (std::error_condition const &err) - { - // return any errors + // find the entry + metadata_entry metaentry; + if (std::error_condition err = metadata_find(metatag, metaindex, metaentry)) return err; - } + + // point the previous to the next, unlinking us + return metadata_set_previous_next(metaentry.prev, metaentry.next); } /** @@ -1542,34 +1665,32 @@ std::error_condition chd_file::delete_metadata(chd_metadata_tag metatag, uint32_ std::error_condition chd_file::clone_all_metadata(chd_file &source) { - // wrap this for clean reporting - try + // iterate over metadata entries in the source + std::vector<uint8_t> filedata; + metadata_entry metaentry; + metaentry.metatag = 0; + metaentry.length = 0; + metaentry.next = 0; + metaentry.flags = 0; + std::error_condition err; + for (err = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); !err; err = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true)) { - // iterate over metadata entries in the source - std::vector<uint8_t> filedata; - metadata_entry metaentry; - metaentry.metatag = 0; - metaentry.length = 0; - metaentry.next = 0; - metaentry.flags = 0; - for (bool has_data = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); has_data; has_data = source.metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true)) - { - // read the metadata item - filedata.resize(metaentry.length); - source.file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length); - - // write it to the destination - std::error_condition err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags); - if (err) - throw err; - } - return std::error_condition(); + // read the metadata item + try { filedata.resize(metaentry.length); } + catch (std::bad_alloc const &) { return std::errc::not_enough_memory; } + err = source.file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length); + if (UNEXPECTED(err)) + return err; + + // write it to the destination + err = write_metadata(metaentry.metatag, (uint32_t)-1, &filedata[0], metaentry.length, metaentry.flags); + if (UNEXPECTED(err)) + return err; } - catch (std::error_condition const &err) - { - // return any errors + if (err == error::METADATA_NOT_FOUND) + return std::error_condition(); + else return err; - } } /** @@ -1595,15 +1716,18 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1) std::vector<uint8_t> filedata; std::vector<metadata_hash> hasharray; metadata_entry metaentry; - for (bool has_data = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); has_data; has_data = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true)) + std::error_condition err; + for (err = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry); !err; err = metadata_find(CHDMETATAG_WILDCARD, 0, metaentry, true)) { // if not checksumming, continue - if ((metaentry.flags & CHD_MDFLAGS_CHECKSUM) == 0) + if (!(metaentry.flags & CHD_MDFLAGS_CHECKSUM)) continue; // allocate memory and read the data filedata.resize(metaentry.length); - file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length); + err = file_read(metaentry.offset + METADATA_HEADER_SIZE, &filedata[0], metaentry.length); + if (UNEXPECTED(err)) + throw err; // create an entry for this metadata and add it metadata_hash hashentry; @@ -1611,6 +1735,8 @@ util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1) hashentry.sha1 = util::sha1_creator::simple(&filedata[0], metaentry.length); hasharray.push_back(hashentry); } + if (err != error::METADATA_NOT_FOUND) + throw err; // sort the array if (!hasharray.empty()) @@ -1772,7 +1898,7 @@ uint32_t chd_file::guess_unitbytes() void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length - if (get_u32be(&rawheader[8]) != V3_HEADER_SIZE) + if (UNEXPECTED(get_u32be(&rawheader[8]) != V3_HEADER_SIZE)) throw std::error_condition(error::INVALID_FILE); // extract core info @@ -1835,7 +1961,7 @@ void chd_file::parse_v3_header(uint8_t *rawheader, util::sha1_t &parentsha1) void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length - if (get_u32be(&rawheader[8]) != V4_HEADER_SIZE) + if (UNEXPECTED(get_u32be(&rawheader[8]) != V4_HEADER_SIZE)) throw std::error_condition(error::INVALID_FILE); // extract core info @@ -1895,7 +2021,7 @@ void chd_file::parse_v4_header(uint8_t *rawheader, util::sha1_t &parentsha1) void chd_file::parse_v5_header(uint8_t *rawheader, util::sha1_t &parentsha1) { // verify header length - if (get_u32be(&rawheader[8]) != V5_HEADER_SIZE) + if (UNEXPECTED(get_u32be(&rawheader[8]) != V5_HEADER_SIZE)) throw std::error_condition(error::INVALID_FILE); // extract core info @@ -1969,9 +2095,9 @@ std::error_condition chd_file::compress_v5_map() { uint8_t curcomp = m_rawmap[hunknum * 12 + 0]; - // promote self block references to more compact forms if (curcomp == COMPRESSION_SELF) { + // promote self block references to more compact forms uint32_t refhunk = get_u48be(&m_rawmap[hunknum * 12 + 4]); if (refhunk == last_self) curcomp = COMPRESSION_SELF_0; @@ -1981,10 +2107,9 @@ std::error_condition chd_file::compress_v5_map() max_self = std::max(max_self, refhunk); last_self = refhunk; } - - // promote parent block references to more compact forms else if (curcomp == COMPRESSION_PARENT) { + // promote parent block references to more compact forms uint32_t refunit = get_u48be(&m_rawmap[hunknum * 12 + 4]); if (refunit == mulu_32x32(hunknum, m_hunkbytes) / m_unitbytes) curcomp = COMPRESSION_PARENT_SELF; @@ -2032,26 +2157,37 @@ std::error_condition chd_file::compress_v5_map() } } - // compute a tree and export it to the buffer - std::vector<uint8_t> compressed(m_hunkcount * 6); + // determine the number of bits we need to hold the a length and a hunk index + const uint8_t lengthbits = bits_for_value(max_complen); + const uint8_t selfbits = bits_for_value(max_self); + const uint8_t parentbits = bits_for_value(max_parent); + + // determine the needed size of the output buffer + // 16 bytes is required for the header + // max len per entry given to huffman encoder at instantiation is 8 bits + // this corresponds to worst-case max 12 bits per entry when RLE encoded. + // max additional bits per entry after RLE encoded tree is + // for COMPRESSION_TYPE_0-3: lengthbits+16 + // for COMPRESSION_NONE: 16 + // for COMPRESSION_SELF: selfbits + // for COMPRESSION_PARENT: parentbits + // the overall size is clamped later with bitbuf.flush() + int nbits_needed = (8*16) + (12 + std::max<int>({lengthbits+16, selfbits, parentbits}))*m_hunkcount; + std::vector<uint8_t> compressed(nbits_needed / 8 + 1); bitstream_out bitbuf(&compressed[16], compressed.size() - 16); + + // compute a tree and export it to the buffer huffman_error err = encoder.compute_tree_from_histo(); - if (err != HUFFERR_NONE) + if (UNEXPECTED(err != HUFFERR_NONE)) throw std::error_condition(error::COMPRESSION_ERROR); err = encoder.export_tree_rle(bitbuf); - if (err != HUFFERR_NONE) + if (UNEXPECTED(err != HUFFERR_NONE)) throw std::error_condition(error::COMPRESSION_ERROR); // encode the data for (uint8_t *src = &compression_rle[0]; src < dest; src++) encoder.encode_one(bitbuf, *src); - // determine the number of bits we need to hold the a length - // and a hunk index - uint8_t lengthbits = bits_for_value(max_complen); - uint8_t selfbits = bits_for_value(max_self); - uint8_t parentbits = bits_for_value(max_parent); - // for each compression type, output the relevant data lastcomp = 0; count = 0; @@ -2134,13 +2270,16 @@ std::error_condition chd_file::compress_v5_map() // then write the map offset uint8_t rawbuf[sizeof(uint64_t)]; put_u64be(rawbuf, m_mapoffset); - file_write(m_mapoffset_offset, rawbuf, sizeof(rawbuf)); - return std::error_condition(); + return file_write(m_mapoffset_offset, rawbuf, sizeof(rawbuf)); } catch (std::error_condition const &err) { return err; } + catch (std::bad_alloc const &) + { + return std::errc::not_enough_memory; + } } /** @@ -2165,7 +2304,10 @@ void chd_file::decompress_v5_map() // read the reader uint8_t rawbuf[16]; - file_read(m_mapoffset, rawbuf, sizeof(rawbuf)); + std::error_condition ioerr; + ioerr = file_read(m_mapoffset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(ioerr)) + throw ioerr; uint32_t const mapbytes = get_u32be(&rawbuf[0]); uint64_t const firstoffs = get_u48be(&rawbuf[4]); util::crc16_t const mapcrc = get_u16be(&rawbuf[10]); @@ -2175,13 +2317,15 @@ void chd_file::decompress_v5_map() // now read the map std::vector<uint8_t> compressed(mapbytes); - file_read(m_mapoffset + 16, &compressed[0], mapbytes); + ioerr = file_read(m_mapoffset + 16, &compressed[0], mapbytes); + if (UNEXPECTED(ioerr)) + throw ioerr; bitstream_in bitbuf(&compressed[0], compressed.size()); // first decode the compression types huffman_decoder<16, 8> decoder; - huffman_error err = decoder.import_tree_rle(bitbuf); - if (err != HUFFERR_NONE) + huffman_error const huferr = decoder.import_tree_rle(bitbuf); + if (UNEXPECTED(huferr != HUFFERR_NONE)) throw std::error_condition(error::DECOMPRESSION_ERROR); uint8_t lastcomp = 0; int repcount = 0; @@ -2265,7 +2409,7 @@ void chd_file::decompress_v5_map() } // verify the final CRC - if (util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc) + if (UNEXPECTED(util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc)) throw std::error_condition(error::DECOMPRESSION_ERROR); } @@ -2295,13 +2439,13 @@ std::error_condition chd_file::create_common() m_metaoffset = 0; // if we have a parent, it must be V3 or later - if (m_parent && m_parent->version() < 3) + if (UNEXPECTED(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) + if (UNEXPECTED(m_hunkbytes % m_unitbytes != 0)) throw std::error_condition(std::errc::invalid_argument); - if (m_parent && m_unitbytes != m_parent->unit_bytes()) + if (UNEXPECTED(m_parent && m_unitbytes != m_parent->unit_bytes())) throw std::error_condition(std::errc::invalid_argument); // verify the compression types @@ -2336,7 +2480,9 @@ std::error_condition chd_file::create_common() be_write_sha1(&rawheader[104], m_parent ? m_parent->sha1() : util::sha1_t::null); // write the resulting header - file_write(0, rawheader, sizeof(rawheader)); + std::error_condition err = file_write(0, rawheader, sizeof(rawheader)); + if (UNEXPECTED(err)) + throw err; // parse it back out to set up fields appropriately util::sha1_t parentsha1; @@ -2354,8 +2500,10 @@ std::error_condition chd_file::create_common() uint64_t offset = m_mapoffset; while (mapsize != 0) { - uint32_t bytes_to_write = (std::min<size_t>)(mapsize, sizeof(buffer)); - file_write(offset, buffer, bytes_to_write); + uint32_t const bytes_to_write = std::min<size_t>(mapsize, sizeof(buffer)); + err = file_write(offset, buffer, bytes_to_write); + if (UNEXPECTED(err)) + throw err; offset += bytes_to_write; mapsize -= bytes_to_write; } @@ -2411,10 +2559,12 @@ std::error_condition chd_file::open_common(bool writeable, const open_parent_fun // read the raw header uint8_t rawheader[MAX_HEADER_SIZE]; - file_read(0, rawheader, sizeof(rawheader)); + std::error_condition err = file_read(0, rawheader, sizeof(rawheader)); + if (UNEXPECTED(err)) + throw err; // verify the signature - if (memcmp(rawheader, "MComprHD", 8) != 0) + if (UNEXPECTED(memcmp(rawheader, "MComprHD", 8) != 0)) throw std::error_condition(error::INVALID_FILE); m_version = get_u32be(&rawheader[12]); @@ -2433,7 +2583,7 @@ std::error_condition chd_file::open_common(bool writeable, const open_parent_fun if (m_version < HEADER_VERSION) m_allow_writes = false; - if (writeable && !m_allow_writes) + if (UNEXPECTED(writeable && !m_allow_writes)) 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) @@ -2447,7 +2597,7 @@ std::error_condition chd_file::open_common(bool writeable, const open_parent_fun else if (m_parent->sha1() != parentsha1) throw std::error_condition(error::INVALID_PARENT); } - else if (m_parent) + else if (UNEXPECTED(m_parent)) { throw std::error_condition(std::errc::invalid_argument); } @@ -2481,16 +2631,22 @@ void chd_file::create_open_common() for (int decompnum = 0; decompnum < std::size(m_compression); decompnum++) { m_decompressor[decompnum] = chd_codec_list::new_decompressor(m_compression[decompnum], *this); - if (m_decompressor[decompnum] == nullptr && m_compression[decompnum] != 0) + if (UNEXPECTED(!m_decompressor[decompnum] && (m_compression[decompnum] != 0))) throw std::error_condition(error::UNKNOWN_COMPRESSION); } // read the map; v5+ compressed drives need to read and decompress their map m_rawmap.resize(m_hunkcount * m_mapentrybytes); if (m_version >= 5 && compressed()) + { decompress_v5_map(); + } else - file_read(m_mapoffset, &m_rawmap[0], m_rawmap.size()); + { + std::error_condition err = file_read(m_mapoffset, &m_rawmap[0], m_rawmap.size()); + if (UNEXPECTED(err)) + throw err; + } // allocate the temporary compressed buffer and a buffer for caching m_compressed.resize(m_hunkbytes); @@ -2505,44 +2661,37 @@ void chd_file::create_open_common() * for appending to a compressed CHD * -------------------------------------------------. * - * @exception CHDERR_NOT_OPEN Thrown when a chderr not open error condition occurs. - * @exception CHDERR_HUNK_OUT_OF_RANGE Thrown when a chderr hunk out of range error - * condition occurs. - * @exception CHDERR_FILE_NOT_WRITEABLE Thrown when a chderr file not writeable error - * condition occurs. - * @exception CHDERR_COMPRESSION_ERROR Thrown when a chderr compression error error - * condition occurs. - * * @param hunknum The hunknum. */ -void chd_file::verify_proper_compression_append(uint32_t hunknum) +std::error_condition chd_file::verify_proper_compression_append(uint32_t hunknum) const noexcept { // punt if no file - if (!m_file) - throw std::error_condition(error::NOT_OPEN); + if (UNEXPECTED(!m_file)) + return std::error_condition(error::NOT_OPEN); // return an error if out of range - if (hunknum >= m_hunkcount) - throw std::error_condition(error::HUNK_OUT_OF_RANGE); + if (UNEXPECTED(hunknum >= m_hunkcount)) + return std::error_condition(error::HUNK_OUT_OF_RANGE); // if not writeable, fail - if (!m_allow_writes) - throw std::error_condition(error::FILE_NOT_WRITEABLE); + if (UNEXPECTED(!m_allow_writes)) + return std::error_condition(error::FILE_NOT_WRITEABLE); // compressed writes only via this interface - if (!compressed()) - throw std::error_condition(error::FILE_NOT_WRITEABLE); + if (UNEXPECTED(!compressed())) + return 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 std::error_condition(error::COMPRESSION_ERROR); + uint8_t const *const rawmap = &m_rawmap[hunknum * 12]; + if (UNEXPECTED(rawmap[0] != 0xff)) + return std::error_condition(error::COMPRESSION_ERROR); + + // if this isn't the first block, only permitted to write immediately after the previous one + if (UNEXPECTED((hunknum != 0) && (rawmap[-12] == 0xff))) + return 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 std::error_condition(error::COMPRESSION_ERROR); + return std::error_condition(); } /** @@ -2563,7 +2712,9 @@ void chd_file::verify_proper_compression_append(uint32_t hunknum) void chd_file::hunk_write_compressed(uint32_t hunknum, int8_t compression, const uint8_t *compressed, uint32_t complength, util::crc16_t crc16) { // verify that we are appending properly to a compressed file - verify_proper_compression_append(hunknum); + std::error_condition err = verify_proper_compression_append(hunknum); + if (UNEXPECTED(err)) + throw err; // write the final result uint64_t offset = file_append(compressed, complength); @@ -2593,11 +2744,13 @@ void chd_file::hunk_write_compressed(uint32_t hunknum, int8_t compression, const void chd_file::hunk_copy_from_self(uint32_t hunknum, uint32_t otherhunk) { // verify that we are appending properly to a compressed file - verify_proper_compression_append(hunknum); + std::error_condition err = verify_proper_compression_append(hunknum); + if (UNEXPECTED(err)) + throw err; // only permitted to reference prior hunks - if (otherhunk >= hunknum) - throw std::error_condition(std::errc::invalid_argument); + if (UNEXPECTED(otherhunk >= hunknum)) + throw std::error_condition(error::HUNK_OUT_OF_RANGE); // update the map entry uint8_t *rawmap = &m_rawmap[hunknum * 12]; @@ -2621,10 +2774,12 @@ void chd_file::hunk_copy_from_self(uint32_t hunknum, uint32_t otherhunk) void chd_file::hunk_copy_from_parent(uint32_t hunknum, uint64_t parentunit) { // verify that we are appending properly to a compressed file - verify_proper_compression_append(hunknum); + std::error_condition err = verify_proper_compression_append(hunknum); + if (UNEXPECTED(err)) + throw err; // update the map entry - uint8_t *rawmap = &m_rawmap[hunknum * 12]; + uint8_t *const rawmap = &m_rawmap[hunknum * 12]; rawmap[0] = COMPRESSION_PARENT; put_u24be(&rawmap[1], 0); put_u48be(&rawmap[4], parentunit); @@ -2632,7 +2787,7 @@ void chd_file::hunk_copy_from_parent(uint32_t hunknum, uint64_t parentunit) } /** - * @fn bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume) + * @fn std::error_condition chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume) * * @brief ------------------------------------------------- * metadata_find - find a metadata entry @@ -2643,10 +2798,10 @@ void chd_file::hunk_copy_from_parent(uint32_t hunknum, uint64_t parentunit) * @param [in,out] metaentry The metaentry. * @param resume true to resume. * - * @return true if it succeeds, false if it fails. + * @return A std::error_condition (error::METADATA_NOT_FOUND if the search fails). */ -bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume) const +std::error_condition chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume) const noexcept { // start at the beginning unless we're resuming a previous search if (!resume) @@ -2665,7 +2820,9 @@ bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metada { // read the raw header uint8_t raw_meta_header[METADATA_HEADER_SIZE]; - file_read(metaentry.offset, raw_meta_header, sizeof(raw_meta_header)); + std::error_condition err = file_read(metaentry.offset, raw_meta_header, sizeof(raw_meta_header)); + if (UNEXPECTED(err)) + return err; // extract the data metaentry.metatag = get_u32be(&raw_meta_header[0]); @@ -2676,7 +2833,7 @@ bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metada // if we got a match, proceed if (metatag == CHDMETATAG_WILDCARD || metaentry.metatag == metatag) if (metaindex-- == 0) - return true; + return std::error_condition(); // no match, fetch the next link metaentry.prev = metaentry.offset; @@ -2684,7 +2841,7 @@ bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metada } // if we get here, we didn't find it - return false; + return error::METADATA_NOT_FOUND; } /** @@ -2698,27 +2855,28 @@ bool chd_file::metadata_find(chd_metadata_tag metatag, int32_t metaindex, metada * @param nextoffset The nextoffset. */ -void chd_file::metadata_set_previous_next(uint64_t prevoffset, uint64_t nextoffset) +std::error_condition chd_file::metadata_set_previous_next(uint64_t prevoffset, uint64_t nextoffset) noexcept { uint64_t offset = 0; - // if we were the first entry, make the next entry the first if (prevoffset == 0) { + // if we were the first entry, make the next entry the first offset = m_metaoffset_offset; m_metaoffset = nextoffset; } - - // otherwise, update the link in the previous header else + { + // otherwise, update the link in the previous header offset = prevoffset + 8; + } // create a big-endian version uint8_t rawbuf[sizeof(uint64_t)]; put_u64be(rawbuf, nextoffset); // write to the header and update our local copy - file_write(offset, rawbuf, sizeof(rawbuf)); + return file_write(offset, rawbuf, sizeof(rawbuf)); } /** @@ -2732,7 +2890,7 @@ void chd_file::metadata_set_previous_next(uint64_t prevoffset, uint64_t nextoffs void chd_file::metadata_update_hash() { // only works for V4 and above, and only for compressed CHDs - if (m_version < 4 || !compressed()) + if ((m_version < 4) || !compressed()) return; // compute the new overall hash @@ -2743,7 +2901,9 @@ void chd_file::metadata_update_hash() be_write_sha1(&rawbuf[0], fullsha1); // write to the header - file_write(m_sha1_offset, rawbuf, sizeof(rawbuf)); + std::error_condition err = file_write(m_sha1_offset, rawbuf, sizeof(rawbuf)); + if (UNEXPECTED(err)) + throw err; } /** @@ -2778,19 +2938,18 @@ int CLIB_DECL chd_file::metadata_hash_compare(const void *elem1, const void *ele * -------------------------------------------------. */ -chd_file_compressor::chd_file_compressor() - : m_walking_parent(false), - m_total_in(0), - m_total_out(0), - m_read_queue(nullptr), - m_read_queue_offset(0), - m_read_done_offset(0), - m_read_error(false), - m_work_queue(nullptr), - m_write_hunk(0) +chd_file_compressor::chd_file_compressor() : + m_walking_parent(false), + m_total_in(0), + m_total_out(0), + m_read_queue(nullptr), + m_read_queue_offset(0), + m_read_done_offset(0), + m_work_queue(nullptr), + m_write_hunk(0) { // zap arrays - memset(m_codecs, 0, sizeof(m_codecs)); + std::fill(std::begin(m_codecs), std::end(m_codecs), nullptr); // allocate work queues m_read_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_IO); @@ -2839,7 +2998,7 @@ void chd_file_compressor::compress_begin() // reset read state m_read_queue_offset = 0; m_read_done_offset = 0; - m_read_error = false; + m_read_error.clear(); // reset work item state m_work_buffer.resize(hunk_bytes() * (WORK_BUFFER_HUNKS + 1)); @@ -2880,20 +3039,19 @@ void chd_file_compressor::compress_begin() 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 std::errc::io_error; + // if we got an error, return the error + if (UNEXPECTED(m_read_error)) + return m_read_error; // if done reading, queue some more while (m_read_queue_offset < m_logicalbytes && osd_work_queue_items(m_read_queue) < 2) { // see if we have enough free work items to read the next half of a buffer - uint32_t startitem = m_read_queue_offset / hunk_bytes(); - uint32_t enditem = startitem + WORK_BUFFER_HUNKS / 2; - uint32_t curitem; - for (curitem = startitem; curitem < enditem; curitem++) - if (m_work_item[curitem % WORK_BUFFER_HUNKS].m_status != WS_READY) - break; + uint32_t const startitem = m_read_queue_offset / hunk_bytes(); + uint32_t const enditem = startitem + WORK_BUFFER_HUNKS / 2; + uint32_t curitem = startitem; + while ((curitem < enditem) && (m_work_item[curitem % WORK_BUFFER_HUNKS].m_status == WS_READY)) + ++curitem; // if it's not all clear, defer if (curitem != enditem) @@ -2917,64 +3075,60 @@ std::error_condition chd_file_compressor::compress_continue(double &progress, do work_item &item = m_work_item[m_write_hunk % WORK_BUFFER_HUNKS]; // free any OSD work item - if (item.m_osd != nullptr) + if (item.m_osd) + { osd_work_item_release(item.m_osd); - item.m_osd = nullptr; + item.m_osd = nullptr; + } - // for parent walking, just add to the hashmap if (m_walking_parent) { - uint32_t uph = hunk_bytes() / unit_bytes(); + // for parent walking, just add to the hashmap + uint32_t const uph = hunk_bytes() / unit_bytes(); uint32_t units = uph; if (item.m_hunknum == hunk_count() - 1 || !compressed()) units = 1; for (uint32_t unit = 0; unit < units; unit++) + { if (m_parent_map.find(item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1) == hashmap::NOT_FOUND) m_parent_map.add(item.m_hunknum * uph + unit, item.m_hash[unit].m_crc16, item.m_hash[unit].m_sha1); + } } - - // if we're uncompressed, use regular writes else if (!compressed()) { + // if we're uncompressed, use regular writes std::error_condition err = write_hunk(item.m_hunknum, item.m_data); - if (err) + if (UNEXPECTED(err)) return err; // writes of all-0 data don't actually take space, so see if we count this chd_codec_type codec = CHD_CODEC_NONE; uint32_t complen; - hunk_info(item.m_hunknum, codec, complen); - if (codec == CHD_CODEC_NONE) + err = hunk_info(item.m_hunknum, codec, complen); + if (!err && codec == CHD_CODEC_NONE) // TODO: report error? m_total_out += m_hunkbytes; } - - // for compressing, process the result - else do + else if (uint64_t const selfhunk = m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); selfhunk != hashmap::NOT_FOUND) + { + // the hunk is in the self map + hunk_copy_from_self(item.m_hunknum, selfhunk); + } + else { - // first see if the hunk is in the parent or self maps - uint64_t selfhunk = m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); - if (selfhunk != hashmap::NOT_FOUND) + // if not, see if it's in the parent map + uint64_t const parentunit = m_parent ? m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) : hashmap::NOT_FOUND; + if (parentunit != hashmap::NOT_FOUND) { - hunk_copy_from_self(item.m_hunknum, selfhunk); - break; + hunk_copy_from_parent(item.m_hunknum, parentunit); } - - // if not, see if it's in the parent map - if (m_parent) + else { - uint64_t parentunit = m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); - if (parentunit != hashmap::NOT_FOUND) - { - hunk_copy_from_parent(item.m_hunknum, parentunit); - break; - } + // otherwise, append it compressed and add to the self map + hunk_write_compressed(item.m_hunknum, item.m_compression, item.m_compressed, item.m_complen, item.m_hash[0].m_crc16); + m_total_out += item.m_complen; + m_current_map.add(item.m_hunknum, item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); } - - // otherwise, append it compressed and add to the self map - hunk_write_compressed(item.m_hunknum, item.m_compression, item.m_compressed, item.m_complen, item.m_hash[0].m_crc16); - m_total_out += item.m_complen; - m_current_map.add(item.m_hunknum, item.m_hash[0].m_crc16, item.m_hash[0].m_sha1); - } while (false); + } // reset the item and advance item.m_status = WS_READY; @@ -2983,23 +3137,24 @@ std::error_condition chd_file_compressor::compress_continue(double &progress, do // if we hit the end, finalize if (m_write_hunk == m_hunkcount) { - // if this is just walking the parent, reset and get ready for compression if (m_walking_parent) { + // if this is just walking the parent, reset and get ready for compression m_walking_parent = false; m_read_queue_offset = m_read_done_offset = 0; m_write_hunk = 0; - for (auto & elem : m_work_item) + for (auto &elem : m_work_item) elem.m_status = WS_READY; } - - // wait for all reads to finish and if we're compressed, write the final SHA1 and map else { + // wait for all reads to finish and if we're compressed, write the final SHA1 and map osd_work_queue_wait(m_read_queue, 30 * osd_ticks_per_second()); if (!compressed()) return std::error_condition(); - set_raw_sha1(m_compsha1.finish()); + std::error_condition err = set_raw_sha1(m_compsha1.finish()); + if (UNEXPECTED(err)) + return err; return compress_v5_map(); } } @@ -3014,9 +3169,9 @@ std::error_condition chd_file_compressor::compress_continue(double &progress, do // if we're waiting for work, wait // sometimes code can get here with .m_status == WS_READY and .m_osd != nullptr, TODO find out why this happens - while (m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status != WS_READY && - m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status != WS_COMPLETE && - m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd != nullptr) + while ((m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status != WS_READY) && + (m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_status != WS_COMPLETE) && + m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd) osd_work_item_wait(m_work_item[m_write_hunk % WORK_BUFFER_HUNKS].m_osd, osd_ticks_per_second()); return m_walking_parent ? error::WALKING_PARENT : error::COMPRESSING; @@ -3037,7 +3192,7 @@ std::error_condition chd_file_compressor::compress_continue(double &progress, do void *chd_file_compressor::async_walk_parent_static(void *param, int threadid) { - auto *item = reinterpret_cast<work_item *>(param); + auto *const item = reinterpret_cast<work_item *>(param); item->m_compressor->async_walk_parent(*item); return nullptr; } @@ -3079,7 +3234,7 @@ void chd_file_compressor::async_walk_parent(work_item &item) void *chd_file_compressor::async_compress_hunk_static(void *param, int threadid) { - auto *item = reinterpret_cast<work_item *>(param); + auto *const item = reinterpret_cast<work_item *>(param); item->m_compressor->async_compress_hunk(*item, threadid); return nullptr; } @@ -3106,8 +3261,8 @@ void chd_file_compressor::async_compress_hunk(work_item &item, int threadid) // find the best compression scheme, unless we already have a self or parent match // (note we may miss a self match from blocks not yet added, but this just results in extra work) // TODO: data race - if (m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND && - m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND) + if ((m_current_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND) && + (m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1) == hashmap::NOT_FOUND)) item.m_compression = item.m_codecs->find_best_compressor(item.m_data, item.m_compressed, item.m_complen); // mark us complete @@ -3142,37 +3297,45 @@ void *chd_file_compressor::async_read_static(void *param, int threadid) void chd_file_compressor::async_read() { // if in the error or complete state, stop - if (m_read_error) + if (UNEXPECTED(m_read_error)) return; // determine parameters for the read - uint32_t work_buffer_bytes = WORK_BUFFER_HUNKS * hunk_bytes(); + uint32_t const work_buffer_bytes = WORK_BUFFER_HUNKS * hunk_bytes(); uint32_t numbytes = work_buffer_bytes / 2; - if (m_read_done_offset + numbytes > logical_bytes()) + if ((m_read_done_offset + numbytes) > logical_bytes()) numbytes = logical_bytes() - m_read_done_offset; + uint8_t *const dest = &m_work_buffer[0] + (m_read_done_offset % work_buffer_bytes); + assert((&m_work_buffer[0] == dest) || (&m_work_buffer[work_buffer_bytes / 2] == dest)); + assert(!(m_read_done_offset % hunk_bytes())); + uint64_t const end_offset = m_read_done_offset + numbytes; + // catch any exceptions coming out of here try { // do the read - uint8_t *dest = &m_work_buffer[0] + (m_read_done_offset % work_buffer_bytes); - assert(dest == &m_work_buffer[0] || dest == &m_work_buffer[work_buffer_bytes/2]); - uint64_t end_offset = m_read_done_offset + numbytes; - - // if walking the parent, read in hunks from the parent CHD if (m_walking_parent) { + // if walking the parent, read in hunks from the parent CHD + uint64_t curoffs = m_read_done_offset; uint8_t *curdest = dest; - for (uint64_t curoffs = m_read_done_offset; curoffs < end_offset + 1; curoffs += hunk_bytes()) + uint32_t curhunk = m_read_done_offset / hunk_bytes(); + while (curoffs < end_offset + 1) { - m_parent->read_hunk(curoffs / hunk_bytes(), curdest); + std::error_condition err = m_parent->read_hunk(curhunk, curdest); + if (err && (error::HUNK_OUT_OF_RANGE != err)) // FIXME: fix the code so it doesn't depend on trying to read past the end of the parent CHD + throw err; + curoffs += hunk_bytes(); curdest += hunk_bytes(); + ++curhunk; } } - - // otherwise, call the virtual function else + { + // otherwise, call the virtual function read_data(dest, m_read_done_offset, numbytes); + } // spawn off work for each hunk for (uint64_t curoffs = m_read_done_offset; curoffs < end_offset; curoffs += hunk_bytes()) @@ -3199,12 +3362,12 @@ void chd_file_compressor::async_read() catch (std::error_condition const &err) { fprintf(stderr, "CHD error occurred: %s\n", err.message().c_str()); - m_read_error = true; + m_read_error = err; } catch (std::exception const &ex) { fprintf(stderr, "exception occurred: %s\n", ex.what()); - m_read_error = true; + m_read_error = std::errc::io_error; // TODO: revisit this error code } } @@ -3222,8 +3385,8 @@ void chd_file_compressor::async_read() * -------------------------------------------------. */ -chd_file_compressor::hashmap::hashmap() - : m_block_list(new entry_block(nullptr)) +chd_file_compressor::hashmap::hashmap() : + m_block_list(new entry_block(nullptr)) { // initialize the map to empty memset(m_map, 0, sizeof(m_map)); @@ -3279,10 +3442,10 @@ void chd_file_compressor::hashmap::reset() * @return An uint64_t. */ -uint64_t chd_file_compressor::hashmap::find(util::crc16_t crc16, util::sha1_t sha1) +uint64_t chd_file_compressor::hashmap::find(util::crc16_t crc16, util::sha1_t sha1) const noexcept { // look up the entry in the map - for (entry_t *entry = m_map[crc16]; entry != nullptr; entry = entry->m_next) + for (entry_t *entry = m_map[crc16]; entry; entry = entry->m_next) if (entry->m_sha1 == sha1) return entry->m_itemnum; return NOT_FOUND; @@ -3312,36 +3475,40 @@ void chd_file_compressor::hashmap::add(uint64_t itemnum, util::crc16_t crc16, ut m_map[crc16] = entry; } -bool chd_file::is_hd() const +std::error_condition chd_file::check_is_hd() const noexcept { metadata_entry metaentry; return metadata_find(HARD_DISK_METADATA_TAG, 0, metaentry); } -bool chd_file::is_cd() const +std::error_condition chd_file::check_is_cd() const noexcept { metadata_entry metaentry; - return metadata_find(CDROM_OLD_METADATA_TAG, 0, metaentry) - || metadata_find(CDROM_TRACK_METADATA_TAG, 0, metaentry) - || metadata_find(CDROM_TRACK_METADATA2_TAG, 0, metaentry); + std::error_condition err = metadata_find(CDROM_OLD_METADATA_TAG, 0, metaentry); + if (err == error::METADATA_NOT_FOUND) + err = metadata_find(CDROM_TRACK_METADATA_TAG, 0, metaentry); + if (err == error::METADATA_NOT_FOUND) + err = metadata_find(CDROM_TRACK_METADATA2_TAG, 0, metaentry); + return err; } -bool chd_file::is_gd() const +std::error_condition chd_file::check_is_gd() const noexcept { metadata_entry metaentry; - return metadata_find(GDROM_OLD_METADATA_TAG, 0, metaentry) - || metadata_find(GDROM_TRACK_METADATA_TAG, 0, metaentry); + std::error_condition err = metadata_find(GDROM_OLD_METADATA_TAG, 0, metaentry); + if (err == error::METADATA_NOT_FOUND) + err = metadata_find(GDROM_TRACK_METADATA_TAG, 0, metaentry); + return err; } -bool chd_file::is_dvd() const +std::error_condition chd_file::check_is_dvd() const noexcept { metadata_entry metaentry; return metadata_find(DVD_METADATA_TAG, 0, metaentry); } -bool chd_file::is_av() const +std::error_condition chd_file::check_is_av() const noexcept { metadata_entry metaentry; return metadata_find(AV_METADATA_TAG, 0, metaentry); } - diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index 3e52cab4f9b..671f4bdbd01 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -2,8 +2,6 @@ // copyright-holders:Aaron Giles /*************************************************************************** - chd.h - MAME Compressed Hunks of Data file format ***************************************************************************/ @@ -309,24 +307,24 @@ public: uint32_t hunk_count() const noexcept { return m_hunkcount; } uint32_t unit_bytes() const noexcept { return m_unitbytes; } uint64_t unit_count() const noexcept { return m_unitcount; } - bool compressed() const { return (m_compression[0] != CHD_CODEC_NONE); } + bool compressed() const noexcept { return (m_compression[0] != CHD_CODEC_NONE); } chd_codec_type compression(int index) const noexcept { return m_compression[index]; } chd_file *parent() const noexcept { return m_parent.get(); } bool parent_missing() const noexcept; - util::sha1_t sha1(); - util::sha1_t raw_sha1(); - util::sha1_t parent_sha1(); + util::sha1_t sha1() const noexcept; + util::sha1_t raw_sha1() const noexcept; + util::sha1_t parent_sha1() const noexcept; 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); + std::error_condition set_raw_sha1(util::sha1_t rawdata) noexcept; + std::error_condition set_parent_sha1(util::sha1_t parent) noexcept; // file create - 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); + std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, const chd_codec_type (&compression)[4]); + std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, const chd_codec_type (&compression)[4]); + std::error_condition create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, const chd_codec_type (&compression)[4], chd_file &parent); + std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, const chd_codec_type (&compression)[4], chd_file &parent); // file open std::error_condition open(std::string_view filename, bool writeable = false, chd_file *parent = nullptr, const open_parent_func &open_parent = nullptr); @@ -336,6 +334,7 @@ public: void close(); // read/write + std::error_condition codec_process_hunk(uint32_t hunknum); 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); @@ -361,23 +360,23 @@ public: std::error_condition codec_configure(chd_codec_type codec, int param, void *config); // typing - bool is_hd() const; - bool is_cd() const; - bool is_gd() const; - bool is_dvd() const; - bool is_av() const; + std::error_condition check_is_hd() const noexcept; + std::error_condition check_is_cd() const noexcept; + std::error_condition check_is_gd() const noexcept; + std::error_condition check_is_dvd() const noexcept; + std::error_condition check_is_av() const noexcept; private: struct metadata_entry; struct metadata_hash; // inline helpers - util::sha1_t be_read_sha1(const uint8_t *base) const; - void be_write_sha1(uint8_t *base, util::sha1_t value); - void file_read(uint64_t offset, void *dest, uint32_t length) const; - void file_write(uint64_t offset, const void *source, uint32_t length); + util::sha1_t be_read_sha1(const uint8_t *base) const noexcept; + void be_write_sha1(uint8_t *base, util::sha1_t value) noexcept; + std::error_condition file_read(uint64_t offset, void *dest, uint32_t length) const noexcept; + std::error_condition file_write(uint64_t offset, const void *source, uint32_t length) noexcept; uint64_t file_append(const void *source, uint32_t length, uint32_t alignment = 0); - uint8_t bits_for_value(uint64_t value); + static uint8_t bits_for_value(uint64_t value) noexcept; // internal helpers uint32_t guess_unitbytes(); @@ -389,12 +388,12 @@ private: std::error_condition create_common(); std::error_condition open_common(bool writeable, const open_parent_func &open_parent); void create_open_common(); - void verify_proper_compression_append(uint32_t hunknum); + std::error_condition verify_proper_compression_append(uint32_t hunknum) const noexcept; void hunk_write_compressed(uint32_t hunknum, int8_t compression, const uint8_t *compressed, uint32_t complength, util::crc16_t crc16); void hunk_copy_from_self(uint32_t hunknum, uint32_t otherhunk); void hunk_copy_from_parent(uint32_t hunknum, uint64_t parentunit); - bool metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume = false) const; - void metadata_set_previous_next(uint64_t prevoffset, uint64_t nextoffset); + std::error_condition metadata_find(chd_metadata_tag metatag, int32_t metaindex, metadata_entry &metaentry, bool resume = false) const noexcept; + std::error_condition metadata_set_previous_next(uint64_t prevoffset, uint64_t nextoffset) noexcept; void metadata_update_hash(); static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2); @@ -466,7 +465,7 @@ private: // operations void reset(); - uint64_t find(util::crc16_t crc16, util::sha1_t sha1); + uint64_t find(util::crc16_t crc16, util::sha1_t sha1) const noexcept; void add(uint64_t itemnum, util::crc16_t crc16, util::sha1_t sha1); // constants @@ -563,7 +562,7 @@ private: 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 - bool m_read_error; // error during reading? + std::error_condition m_read_error; // error during reading, if any // work item thread static constexpr int WORK_BUFFER_HUNKS = 256; diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp index c59d880374c..c8a1f573bd0 100644 --- a/src/lib/util/chdcodec.cpp +++ b/src/lib/util/chdcodec.cpp @@ -2,8 +2,6 @@ // copyright-holders:Aaron Giles /*************************************************************************** - chdcodec.c - Codecs used by the CHD format ***************************************************************************/ @@ -333,16 +331,16 @@ private: // ======================> chd_cd_compressor -template<class BaseCompressor, class SubcodeCompressor> +template <class BaseCompressor, class SubcodeCompressor> class chd_cd_compressor : public chd_compressor { public: // construction/destruction chd_cd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_base_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy), - m_subcode_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy), - m_buffer(hunkbytes + (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA) + : chd_compressor(chd, hunkbytes, lossy) + , m_base_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy) + , m_subcode_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy) + , m_buffer(hunkbytes + (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA) { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % cdrom_file::FRAME_SIZE != 0) @@ -402,16 +400,16 @@ private: // ======================> chd_cd_decompressor -template<class BaseDecompressor, class SubcodeDecompressor> +template <class BaseDecompressor, class SubcodeDecompressor> class chd_cd_decompressor : public chd_decompressor { public: // construction/destruction chd_cd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_decompressor(chd, hunkbytes, lossy), - m_base_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy), - m_subcode_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy), - m_buffer(hunkbytes) + : chd_decompressor(chd, hunkbytes, lossy) + , m_base_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy) + , m_subcode_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % cdrom_file::FRAME_SIZE != 0) @@ -490,6 +488,7 @@ public: chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy); // core functionality + virtual void process(const uint8_t *src, uint32_t complen) override; virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) override; virtual void configure(int param, void *config) override; @@ -553,7 +552,7 @@ const codec_entry f_codec_list[] = // instance of the given type //------------------------------------------------- -const codec_entry *find_in_list(chd_codec_type type) +const codec_entry *find_in_list(chd_codec_type type) noexcept { // find in the list and construct the class for (auto & elem : f_codec_list) @@ -575,9 +574,9 @@ const codec_entry *find_in_list(chd_codec_type type) //------------------------------------------------- chd_codec::chd_codec(chd_file &chd, uint32_t hunkbytes, bool lossy) - : m_chd(chd), - m_hunkbytes(hunkbytes), - m_lossy(lossy) + : m_chd(chd) + , m_hunkbytes(hunkbytes) + , m_lossy(lossy) { } @@ -607,10 +606,6 @@ void chd_codec::configure(int param, void *config) // CHD COMPRESSOR //************************************************************************** -//------------------------------------------------- -// chd_compressor - constructor -//------------------------------------------------- - chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) : chd_codec(chd, hunkbytes, lossy) { @@ -622,15 +617,16 @@ chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) // CHD DECOMPRESSOR //************************************************************************** -//------------------------------------------------- -// chd_decompressor - constructor -//------------------------------------------------- - chd_decompressor::chd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) : chd_codec(chd, hunkbytes, lossy) { } +void chd_decompressor::process(const uint8_t *src, uint32_t complen) +{ + throw std::error_condition(chd_file::error::UNSUPPORTED_FORMAT); +} + //************************************************************************** @@ -668,7 +664,7 @@ chd_decompressor::ptr chd_codec_list::new_decompressor(chd_codec_type type, chd_ // corresponds to a supported codec //------------------------------------------------- -bool chd_codec_list::codec_exists(chd_codec_type type) +bool chd_codec_list::codec_exists(chd_codec_type type) noexcept { // find in the list and construct the class return bool(find_in_list(type)); @@ -680,7 +676,7 @@ bool chd_codec_list::codec_exists(chd_codec_type type) // codec //------------------------------------------------- -const char *chd_codec_list::codec_name(chd_codec_type type) +const char *chd_codec_list::codec_name(chd_codec_type type) noexcept { // find in the list and construct the class const codec_entry *entry = find_in_list(type); @@ -1588,8 +1584,8 @@ void chd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uin //------------------------------------------------- chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_compressor(chd, hunkbytes, lossy), - m_buffer(hunkbytes) + : chd_compressor(chd, hunkbytes, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % cdrom_file::FRAME_SIZE != 0) @@ -1717,8 +1713,8 @@ uint32_t chd_cd_flac_compressor::blocksize(uint32_t bytes) */ chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy) - : chd_decompressor(chd, hunkbytes, lossy), - m_buffer(hunkbytes) + : chd_decompressor(chd, hunkbytes, lossy) + , m_buffer(hunkbytes) { // make sure the CHD's hunk size is an even multiple of the frame size if (hunkbytes % cdrom_file::FRAME_SIZE != 0) @@ -1943,21 +1939,13 @@ chd_avhuff_decompressor::chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbyt { } -/** - * @fn void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) - * - * @brief ------------------------------------------------- - * decompress - decompress data using the A/V codec - * -------------------------------------------------. - * - * @exception CHDERR_DECOMPRESSION_ERROR Thrown when a chderr decompression error error - * condition occurs. - * - * @param src Source for the. - * @param complen The complen. - * @param [in,out] dest If non-null, destination for the. - * @param destlen The destlen. - */ +void chd_avhuff_decompressor::process(const uint8_t *src, uint32_t complen) +{ + // decode the audio and video + avhuff_error averr = m_decoder.decode_data(src, complen, nullptr); + if (averr != AVHERR_NONE) + throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); +} void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { @@ -1967,12 +1955,9 @@ void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, u throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR); // pad short frames with 0 - if (dest != nullptr) - { - int size = avhuff_encoder::raw_data_size(dest); - if (size < destlen) - memset(dest + size, 0, destlen - size); - } + auto const size = avhuff_encoder::raw_data_size(dest); + if (size < destlen) + memset(dest + size, 0, destlen - size); } /** diff --git a/src/lib/util/chdcodec.h b/src/lib/util/chdcodec.h index c3234ea600d..c477333544f 100644 --- a/src/lib/util/chdcodec.h +++ b/src/lib/util/chdcodec.h @@ -2,8 +2,6 @@ // copyright-holders:Aaron Giles /*************************************************************************** - chdcodec.h - Codecs used by the CHD format ***************************************************************************/ @@ -89,6 +87,7 @@ public: using ptr = std::unique_ptr<chd_decompressor>; // implementation + virtual void process(const uint8_t *src, uint32_t complen); virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) = 0; }; @@ -104,8 +103,8 @@ public: static chd_decompressor::ptr new_decompressor(chd_codec_type type, chd_file &file); // utilities - static bool codec_exists(chd_codec_type type); - static const char *codec_name(chd_codec_type type); + static bool codec_exists(chd_codec_type type) noexcept; + static const char *codec_name(chd_codec_type type) noexcept; }; diff --git a/src/lib/util/corefile.cpp b/src/lib/util/corefile.cpp index 3d5c705ab86..74a742b0306 100644 --- a/src/lib/util/corefile.cpp +++ b/src/lib/util/corefile.cpp @@ -48,13 +48,13 @@ public: virtual std::error_condition tell(std::uint64_t &result) noexcept override { return m_file.tell(result); } virtual std::error_condition length(std::uint64_t &result) noexcept override { return m_file.length(result); } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.read(buffer, length, actual); } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.read_at(offset, buffer, length, actual); } + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.read_some(buffer, length, actual); } + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.read_some_at(offset, buffer, length, actual); } virtual std::error_condition finalize() noexcept override { return m_file.finalize(); } virtual std::error_condition flush() noexcept override { return m_file.flush(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.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 { return m_file.write_at(offset, buffer, length, actual); } + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.write_some(buffer, length, actual); } + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { return m_file.write_some_at(offset, buffer, length, actual); } virtual bool eof() const override { return m_file.eof(); } @@ -167,13 +167,13 @@ public: ~core_in_memory_file() override { purge(); } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override; - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override; virtual std::error_condition finalize() noexcept override { return std::error_condition(); } virtual std::error_condition flush() noexcept override { clear_putback(); return std::error_condition(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; } + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; } + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0; return std::errc::bad_file_descriptor; } void const *buffer() const { return m_data; } @@ -217,13 +217,13 @@ public: } ~core_osd_file() override; - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override; - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override; virtual std::error_condition finalize() noexcept override; virtual std::error_condition flush() noexcept override; - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override; - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override; + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override; virtual std::error_condition truncate(std::uint64_t offset) override; @@ -260,9 +260,8 @@ int core_text_file::getc() { if (!pos) { - std::size_t readlen; std::uint8_t bom[4]; - read(bom, 4, readlen); + auto const [err, readlen] = read(*this, bom, 4); // FIXME: check for errors if (readlen == 4) { if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) @@ -303,15 +302,14 @@ int core_text_file::getc() // fetch the next character // FIXME: all of this plays fast and loose with error checking and seeks backwards far too frequently char16_t utf16_buffer[UTF16_CHAR_MAX]; - auto uchar = char32_t(~0); + char32_t uchar = ~char32_t(0); switch (m_text_type) { default: case text_file_type::OSD: { char default_buffer[16]; - std::size_t readlen; - read(default_buffer, sizeof(default_buffer), readlen); + auto const [err, readlen] = read(*this, default_buffer, sizeof(default_buffer)); if (readlen > 0) { auto const charlen = osd_uchar_from_osdchar(&uchar, default_buffer, readlen / sizeof(default_buffer[0])); @@ -323,8 +321,7 @@ int core_text_file::getc() case text_file_type::UTF8: { char utf8_buffer[UTF8_CHAR_MAX]; - std::size_t readlen; - read(utf8_buffer, sizeof(utf8_buffer), readlen); + auto const [err, readlen] = read(*this, utf8_buffer, sizeof(utf8_buffer)); if (readlen > 0) { auto const charlen = uchar_from_utf8(&uchar, utf8_buffer, readlen / sizeof(utf8_buffer[0])); @@ -335,8 +332,7 @@ int core_text_file::getc() case text_file_type::UTF16BE: { - std::size_t readlen; - read(utf16_buffer, sizeof(utf16_buffer), readlen); + auto const [err, readlen] = read(*this, utf16_buffer, sizeof(utf16_buffer)); if (readlen > 0) { auto const charlen = uchar_from_utf16be(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0])); @@ -347,8 +343,7 @@ int core_text_file::getc() case text_file_type::UTF16LE: { - std::size_t readlen; - read(utf16_buffer, sizeof(utf16_buffer), readlen); + auto const [err, readlen] = read(*this, utf16_buffer, sizeof(utf16_buffer)); if (readlen > 0) { auto const charlen = uchar_from_utf16le(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0])); @@ -360,8 +355,7 @@ int core_text_file::getc() case text_file_type::UTF32BE: { // FIXME: deal with read returning short - std::size_t readlen; - read(&uchar, sizeof(uchar), readlen); + auto const [err, readlen] = read(*this, &uchar, sizeof(uchar)); if (sizeof(uchar) == readlen) uchar = big_endianize_int32(uchar); } @@ -370,8 +364,7 @@ int core_text_file::getc() case text_file_type::UTF32LE: { // FIXME: deal with read returning short - std::size_t readlen; - read(&uchar, sizeof(uchar), readlen); + auto const [err, readlen] = read(*this, &uchar, sizeof(uchar)); if (sizeof(uchar) == readlen) uchar = little_endianize_int32(uchar); } @@ -467,7 +460,7 @@ char *core_text_file::gets(char *s, int n) int core_text_file::puts(std::string_view s) { - // TODO: what to do about write errors or short writes (interrupted)? + // TODO: what to do about write errors? // The API doesn't lend itself to reporting the error as the return // value includes extra bytes inserted like the UTF-8 marker and // carriage returns. @@ -511,8 +504,7 @@ int core_text_file::puts(std::string_view s) // if we overflow, break into chunks if (pconvbuf >= convbuf + std::size(convbuf) - 10) { - std::size_t written; - write(convbuf, pconvbuf - convbuf, written); // FIXME: error ignored here + auto const [err, written] = write(*this, convbuf, pconvbuf - convbuf); // FIXME: error ignored here count += written; pconvbuf = convbuf; } @@ -521,8 +513,7 @@ int core_text_file::puts(std::string_view s) // final flush if (pconvbuf != convbuf) { - std::size_t written; - write(convbuf, pconvbuf - convbuf, written); // FIXME: error ignored here + auto const [err, written] = write(*this, convbuf, pconvbuf - convbuf); // FIXME: error ignored here count += written; } @@ -646,7 +637,7 @@ std::size_t core_basic_file::safe_buffer_copy( // read - read from a file //------------------------------------------------- -std::error_condition core_in_memory_file::read(void *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_in_memory_file::read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept { clear_putback(); @@ -659,7 +650,7 @@ std::error_condition core_in_memory_file::read(void *buffer, std::size_t length, return std::error_condition(); } -std::error_condition core_in_memory_file::read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_in_memory_file::read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept { clear_putback(); @@ -705,17 +696,17 @@ core_osd_file::~core_osd_file() // read - read from a file //------------------------------------------------- -std::error_condition core_osd_file::read(void *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_osd_file::read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept { // since osd_file works like pread/pwrite, implement in terms of read_at // core_osd_file is declared final, so a derived class can't interfere - std::error_condition err = read_at(index(), buffer, length, actual); + std::error_condition err = read_some_at(index(), buffer, length, actual); add_offset(actual); return err; } -std::error_condition core_osd_file::read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_osd_file::read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept { if (!m_file) { @@ -750,18 +741,12 @@ std::error_condition core_osd_file::read_at(std::uint64_t offset, void *buffer, } else { - // read the remainder directly from the file - do - { - // may need to split into chunks if size_t is larger than 32 bits - 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 - actual); - std::uint32_t bytes_read; - err = m_file->read(reinterpret_cast<std::uint8_t *>(buffer) + actual, offset + actual, chunk, bytes_read); - if (err || !bytes_read) - break; + // read the remainder directly from the file - may need to return short if size_t is larger than 32 bits + 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 - actual); + std::uint32_t bytes_read; + err = m_file->read(reinterpret_cast<std::uint8_t *>(buffer) + actual, offset + actual, chunk, bytes_read); + if (!err) actual += bytes_read; - } - while (actual < length); } } @@ -774,17 +759,17 @@ std::error_condition core_osd_file::read_at(std::uint64_t offset, void *buffer, // write - write to a file //------------------------------------------------- -std::error_condition core_osd_file::write(void const *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_osd_file::write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept { // since osd_file works like pread/pwrite, implement in terms of write_at // core_osd_file is declared final, so a derived class can't interfere - std::error_condition err = write_at(index(), buffer, length, actual); + std::error_condition err = write_some_at(index(), buffer, length, actual); add_offset(actual); return err; } -std::error_condition core_osd_file::write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept +std::error_condition core_osd_file::write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept { // flush any buffered char clear_putback(); @@ -792,24 +777,23 @@ std::error_condition core_osd_file::write_at(std::uint64_t offset, void const *b // invalidate any buffered data m_bufferbytes = 0U; - // do the write - may need to split into chunks if size_t is larger than 32 bits - actual = 0U; - while (length) + // do the write - may need to return short if size_t is larger than 32 bits + 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 bytes_written; + std::error_condition err = m_file->write(buffer, offset, chunk, bytes_written); + if (err) { // bytes written 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 bytes_written; - std::error_condition err = m_file->write(buffer, offset, chunk, bytes_written); - if (err) - return err; + actual = 0U; + } + else + { assert(chunk >= bytes_written); offset += bytes_written; - buffer = reinterpret_cast<std::uint8_t const *>(buffer) + bytes_written; - length -= bytes_written; - actual += bytes_written; + actual = bytes_written; set_size((std::max)(size(), offset)); } - return std::error_condition(); + return err; } @@ -968,7 +952,7 @@ core_file::~core_file() // pointer //------------------------------------------------- -std::error_condition core_file::load(std::string_view filename, void **data, std::uint32_t &length) noexcept +std::error_condition core_file::load(std::string_view filename, void **data, std::size_t &length) noexcept { std::error_condition err; @@ -983,20 +967,20 @@ std::error_condition core_file::load(std::string_view filename, void **data, std err = file->length(size); if (err) return err; - else if (std::uint32_t(size) != size) // TODO: change interface to use size_t rather than uint32_t for output size + else if (std::size_t(size) != size) return std::errc::file_too_large; // allocate memory *data = std::malloc(std::size_t(size)); if (!*data) return std::errc::not_enough_memory; - length = std::uint32_t(size); + length = std::size_t(size); // read the data if (size) { std::size_t actual; - err = file->read(*data, std::size_t(size), actual); + std::tie(err, actual) = read(*file, *data, std::size_t(size)); if (err || (size != actual)) { std::free(*data); @@ -1004,7 +988,7 @@ std::error_condition core_file::load(std::string_view filename, void **data, std if (err) return err; else - return std::errc::io_error; // TODO: revisit this error code - either interrupted by an async signal or file truncated out from under us + return std::errc::io_error; // TODO: revisit this error code - file truncated out from under us } } @@ -1038,14 +1022,14 @@ std::error_condition core_file::load(std::string_view filename, std::vector<uint if (size) { std::size_t actual; - err = file->read(&data[0], std::size_t(size), actual); + std::tie(err, actual) = read(*file, &data[0], std::size_t(size)); if (err || (size != actual)) { data.clear(); if (err) return err; else - return std::errc::io_error; // TODO: revisit this error code - either interrupted by an async signal or file truncated out from under us + return std::errc::io_error; // TODO: revisit this error code - file truncated out from under us } } diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h index 315645d4e2c..fda5015d8ba 100644 --- a/src/lib/util/corefile.h +++ b/src/lib/util/corefile.h @@ -77,7 +77,7 @@ public: virtual char *gets(char *s, int n) = 0; // open a file with the specified filename, read it into memory, and return a pointer - static std::error_condition load(std::string_view filename, void **data, std::uint32_t &length) noexcept; + static std::error_condition load(std::string_view filename, void **data, std::size_t &length) noexcept; static std::error_condition load(std::string_view filename, std::vector<uint8_t> &data) noexcept; diff --git a/src/lib/util/corestr.cpp b/src/lib/util/corestr.cpp index 586f56c1aa3..9fa0a3990a2 100644 --- a/src/lib/util/corestr.cpp +++ b/src/lib/util/corestr.cpp @@ -15,6 +15,7 @@ #include <memory> #include <cctype> +#include <cstdint> #include <cstdlib> diff --git a/src/lib/util/coretmpl.h b/src/lib/util/coretmpl.h index 55313a4a0f5..87f8cfbf09e 100644 --- a/src/lib/util/coretmpl.h +++ b/src/lib/util/coretmpl.h @@ -654,7 +654,7 @@ template <typename T, typename U, typename... V> constexpr T bitswap(T val, U b, /// bit of the input. Specify bits in the order they should appear in /// the output field, from most significant to least significant. /// \return The extracted bits packed into a right-aligned field. -template <unsigned B, typename T, typename... U> T bitswap(T val, U... b) noexcept +template <unsigned B, typename T, typename... U> constexpr T bitswap(T val, U... b) noexcept { static_assert(sizeof...(b) == B, "wrong number of bits"); static_assert((sizeof(std::remove_reference_t<T>) * 8) >= B, "return type too small for result"); diff --git a/src/lib/util/coreutil.cpp b/src/lib/util/coreutil.cpp index 94ec6dec273..cebbceb037e 100644 --- a/src/lib/util/coreutil.cpp +++ b/src/lib/util/coreutil.cpp @@ -10,7 +10,6 @@ #include "coreutil.h" #include <cassert> -#include <zlib.h> /*************************************************************************** @@ -55,14 +54,3 @@ uint32_t bcd_2_dec(uint32_t a) } return result; } - - - -/*************************************************************************** - MISC -***************************************************************************/ - -uint32_t core_crc32(uint32_t crc, const uint8_t *buf, uint32_t len) -{ - return crc32(crc, buf, len); -} diff --git a/src/lib/util/coreutil.h b/src/lib/util/coreutil.h index 1f487232619..813deb27a83 100644 --- a/src/lib/util/coreutil.h +++ b/src/lib/util/coreutil.h @@ -72,11 +72,4 @@ inline int gregorian_days_in_month(int month, int year) return result; } - -/*************************************************************************** - MISC -***************************************************************************/ - -uint32_t core_crc32(uint32_t crc, const uint8_t *buf, uint32_t len); - #endif // MAME_UTIL_COREUTIL_H diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp index 8949f90f146..fb2fd4e2091 100644 --- a/src/lib/util/delegate.cpp +++ b/src/lib/util/delegate.cpp @@ -10,6 +10,8 @@ #include "delegate.h" +#include "mfpresolve.h" + #include <cstdio> #include <sstream> @@ -70,31 +72,9 @@ const delegate_mfp_compatible::raw_mfp_data delegate_mfp_compatible::s_null_mfp delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_generic_class *&object) const { - // apply the "this" delta to the object first - the value is shifted to the left one bit position for the ARM-like variant - LOG("Input this=%p ptr=%p adj=%ld ", reinterpret_cast<void const *>(object), reinterpret_cast<void const *>(m_function), long(m_this_delta)); - object = reinterpret_cast<delegate_generic_class *>( - reinterpret_cast<std::uint8_t *>(object) + (m_this_delta >> ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0))); - LOG("Calculated this=%p ", reinterpret_cast<void const *>(object)); - - // test the virtual member function flag - it's the low bit of either the ptr or adj field, depending on the variant - if ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? !(m_this_delta & 1) : !(m_function & 1)) - { - // conventional function pointer - LOG("ptr=%p\n", reinterpret_cast<void const *>(m_function)); - return reinterpret_cast<delegate_generic_function>(m_function); - } - else - { - // byte index into the vtable to the function - std::uint8_t const *const vtable_ptr = *reinterpret_cast<std::uint8_t const *const *>(object) + m_function - ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 0 : 1); - delegate_generic_function result; - if (MAME_ABI_CXX_VTABLE_FNDESC) - result = reinterpret_cast<delegate_generic_function>(uintptr_t(vtable_ptr)); - else - result = *reinterpret_cast<delegate_generic_function const *>(vtable_ptr); - LOG("ptr=%p (vtable)\n", reinterpret_cast<void const *>(result)); - return result; - } + auto const [entrypoint, adjusted] = resolve_member_function_itanium(m_function, m_this_delta, object); + object = reinterpret_cast<delegate_generic_class *>(adjusted); + return reinterpret_cast<delegate_generic_function>(entrypoint); } @@ -107,181 +87,9 @@ delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_gene delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) const { - LOG("Input this=%p ", reinterpret_cast<void const *>(object)); - if (sizeof(single_base_equiv) < m_size) - LOG("thisdelta=%d ", m_this_delta); - if (sizeof(unknown_base_equiv) == m_size) - LOG("vptrdelta=%d vindex=%d ", m_vptr_offs, m_vt_index); - std::uint8_t *byteptr = reinterpret_cast<std::uint8_t *>(object); - - // test for pointer to member function cast across virtual inheritance relationship - if ((sizeof(unknown_base_equiv) == m_size) && m_vt_index) - { - // add offset from "this" pointer to location of vptr, and add offset to virtual base from vtable - byteptr += m_vptr_offs; - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr); - byteptr += *reinterpret_cast<int const *>(vptr + m_vt_index); - } - - // add "this" pointer displacement if present in the pointer to member function - if (sizeof(single_base_equiv) < m_size) - byteptr += m_this_delta; - LOG("Calculated this=%p\n", reinterpret_cast<void const *>(byteptr)); - object = reinterpret_cast<delegate_generic_class *>(byteptr); - - // walk past recognisable thunks -#if defined(__x86_64__) || defined(_M_X64) - std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function); - while (true) - { - // Assumes Windows calling convention, and doesn't consider that - // the "this" pointer could be in RDX if RCX is a pointer to - // space for an oversize scalar result. Since the result area - // is uninitialised on entry, you won't see something that looks - // like a vtable dispatch through RCX in this case - it won't - // behave badly, it just won't bypass virtual call thunks in the - // rare situations where the return type is an oversize scalar. - if (0xe9 == func[0]) - { - // relative jump with 32-bit displacement (typically a resolved PLT entry) - LOG("Found relative jump at %p ", func); - func += std::ptrdiff_t(5) + *reinterpret_cast<std::int32_t const *>(func + 1); - LOG("redirecting to %p\n", func); - continue; - } - else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2])) - { - if ((0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) - { - // MSVC virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] - LOG("Found virtual member function thunk at %p ", func); - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - if (0x20 == func[4]) // no displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr); - else if (0x60 == func[4]) // 8-bit displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); - else // 32-bit displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); - LOG("redirecting to %p\n", func); - continue; - } - else if ((0x48 == func[3]) && (0x8b == func[4])) - { - // clang virtual function call thunk - mov rax,QWORD PTR [rcx] ; mov rax,QWORD PTR [rax+...] ; jmp rax - if ((0x00 == func[5]) && (0x48 == func[6]) && (0xff == func[7]) && (0xe0 == func[8])) - { - // no displacement - LOG("Found virtual member function thunk at %p ", func); - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - func = *reinterpret_cast<std::uint8_t const *const *>(vptr); - LOG("redirecting to %p\n", func); - continue; - } - else if ((0x40 == func[5]) && (0x48 == func[7]) && (0xff == func[8]) && (0xe0 == func[9])) - { - // 8-bit displacement - LOG("Found virtual member function thunk at %p ", func); - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 6)); - LOG("redirecting to %p\n", func); - continue; - } - else if ((0x80 == func[5]) && (0x48 == func[10]) && (0xff == func[11]) && (0xe0 == func[12])) - { - // 32-bit displacement - LOG("Found virtual member function thunk at %p ", func); - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 6)); - LOG("redirecting to %p\n", func); - continue; - } - } - } - - // clang uses unoptimised thunks if optimisation is disabled - // Without optimisation, clang produces thunks like: - // 50 push rax - // 48 89 0c 24 mov QWORD PTR [rsp],rcx - // 48 8b 0c 24 mov rcx,QWORD PTR [rsp] - // 48 8b 01 mov rax,QWORD PTR [rcx] - // 48 8b 80 xx xx xx xx mov rax,QWORD PTR [rax+...] - // 41 5a pop r10 - // 48 ff e0 jmp rax - // Trying to decode these thunks likely isn't worth the effort. - // Chasing performance in unoptimised builds isn't very useful, - // and the format of these thunks may be fragile. - - // not something we can easily bypass - break; - } - return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); -#elif defined(__aarch64__) || defined(_M_ARM64) - std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(m_function); - while (true) - { - // Assumes little Endian mode. Instructions are always stored - // in little Endian format on AArch64, so if big Endian mode is - // to be supported, the values need to be swapped. - if ((0x90000010 == (func[0] & 0x9f00001f)) && (0x91000210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) - { - // page-relative jump with +/-4GB reach - adrp xip0,... ; add xip0,xip0,#... ; br xip0 - LOG("Found page-relative jump at %p ", func); - std::int64_t const page = - (std::uint64_t(func[0] & 0x60000000) >> 17) | - (std::uint64_t(func[0] & 0x00ffffe0) << 9) | - ((func[0] & 0x00800000) ? (~std::uint64_t(0) << 33) : 0); - std::uint32_t const offset = (func[1] & 0x003ffc00) >> 10; - func = reinterpret_cast<std::uint32_t const *>(((std::uintptr_t(func) + page) & (~std::uintptr_t(0) << 12)) + offset); - LOG("redirecting to %p\n", func); - } - else if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) - { - // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0 - LOG("Found virtual member function thunk at %p ", func); - std::uint32_t const *const *const vptr = *reinterpret_cast<std::uint32_t const *const *const *>(object); - func = vptr[(func[1] & 0x003ffc00) >> 10]; - LOG("redirecting to %p\n", func); - } - else - { - // not something we can easily bypass - break; - } - - // clang uses horribly sub-optimal thunks for AArch64 - // Without optimisation, clang produces thunks like: - // d10143ff sub sp,sp,#80 - // f90027e7 str x7,[sp,#72] - // f90023e6 str x6,[sp,#64] - // f9001fe5 str x5,[sp,#56] - // f9001be4 str x4,[sp,#48] - // f90017e3 str x3,[sp,#40] - // f90013e2 str x2,[sp,#32] - // f9000fe1 str x1,[sp,#24] - // f90007e0 str x0,[sp,#8] - // f94007e0 ldr x0,[sp,#8] - // f9400009 ldr x9,[x0] - // f9400129 ldr x9,[x9,#...] - // 910143ff add sp,sp,#80 - // d61f0120 br x9 - // With optimisation, clang produces thunks like: - // d10103ff sub sp,sp,#64 - // a9008be1 stp x1,x2,[sp,#8] - // a90193e3 stp x3,x4,[sp,#24] - // a9029be5 stp x5,x6,[sp,#40] - // f9001fe7 str x7,[sp,#56] - // f9400009 ldr x9,[x0] - // f9400129 ldr x9,[x9,#...] - // 910103ff add sp,sp,#64 - // d61f0120 br x9 - // It's more effort than it's worth to try decoding these - // thunks. - - } - return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); -#else - return reinterpret_cast<delegate_generic_function>(m_function); -#endif + auto const [entrypoint, adjusted] = resolve_member_function_msvc(&m_function, m_size, object); + object = reinterpret_cast<delegate_generic_class *>(adjusted); + return reinterpret_cast<delegate_generic_function>(entrypoint); } } // namespace util::detail diff --git a/src/lib/util/dvdrom.cpp b/src/lib/util/dvdrom.cpp index 36dc29e7215..0b2379ef7e6 100644 --- a/src/lib/util/dvdrom.cpp +++ b/src/lib/util/dvdrom.cpp @@ -58,8 +58,8 @@ dvdrom_file::dvdrom_file(chd_file *_chd) throw nullptr; /* check it's actually a DVD-ROM */ - if (!chd->is_dvd()) - throw nullptr; + if (std::error_condition err = chd->check_is_dvd()) + throw err; sector_count = chd->unit_count(); } diff --git a/src/lib/util/flac.cpp b/src/lib/util/flac.cpp index 4d6a3bca81b..d3110ca0d38 100644 --- a/src/lib/util/flac.cpp +++ b/src/lib/util/flac.cpp @@ -18,6 +18,7 @@ #include <cstring> #include <iterator> #include <new> +#include <tuple> //************************************************************************** @@ -84,6 +85,8 @@ bool flac_encoder::reset() FLAC__stream_encoder_set_blocksize(m_encoder, m_block_size); // re-start processing + if (m_file) + return (FLAC__stream_encoder_init_stream(m_encoder, write_callback_static, seek_callback_static, tell_callback_static, nullptr, this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK); return (FLAC__stream_encoder_init_stream(m_encoder, write_callback_static, nullptr, nullptr, nullptr, this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK); } @@ -266,8 +269,7 @@ FLAC__StreamEncoderWriteStatus flac_encoder::write_callback(const FLAC__byte buf int count = bytes - offset; if (m_file) { - size_t actual; - m_file->write(buffer, count, actual); // TODO: check for errors + /*auto const [err, actual] =*/ write(*m_file, buffer, count); // FIXME: check for errors } else { @@ -281,6 +283,38 @@ FLAC__StreamEncoderWriteStatus flac_encoder::write_callback(const FLAC__byte buf return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } +FLAC__StreamEncoderSeekStatus flac_encoder::seek_callback_static(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + return reinterpret_cast<flac_encoder *>(client_data)->seek_callback(absolute_byte_offset); +} + +FLAC__StreamEncoderSeekStatus flac_encoder::seek_callback(FLAC__uint64 absolute_byte_offset) +{ + if (m_file) + { + if (!m_file->seek(absolute_byte_offset, SEEK_SET)) + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + } + return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; +} + +FLAC__StreamEncoderTellStatus flac_encoder::tell_callback_static(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + return reinterpret_cast<flac_encoder *>(client_data)->tell_callback(absolute_byte_offset); +} + +FLAC__StreamEncoderTellStatus flac_encoder::tell_callback(FLAC__uint64 *absolute_byte_offset) +{ + if (m_file) + { + if (!m_file->tell(*absolute_byte_offset)) + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + } + return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; +} + //************************************************************************** @@ -537,7 +571,8 @@ FLAC__StreamDecoderReadStatus flac_decoder::read_callback(FLAC__byte buffer[], s if (m_file) // if a file, just read { - m_file->read(buffer, expected, *bytes); // TODO: check for errors + std::error_condition err; + std::tie(err, *bytes) = read(*m_file, buffer, expected); // FIXME: check for errors } else // otherwise, copy from memory { @@ -601,12 +636,12 @@ FLAC__StreamDecoderTellStatus flac_decoder::tell_callback_static(const FLAC__Str // stream //------------------------------------------------- -FLAC__StreamDecoderWriteStatus flac_decoder::write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +FLAC__StreamDecoderWriteStatus flac_decoder::write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { return reinterpret_cast<flac_decoder *>(client_data)->write_callback(frame, buffer); } -FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { assert(frame->header.channels == channels()); @@ -633,7 +668,7 @@ FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame } } -template <flac_decoder::DECODE_MODE Mode, bool SwapEndian> FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +template <flac_decoder::DECODE_MODE Mode, bool SwapEndian> FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { const int blocksize = frame->header.blocksize; const int shift = (Mode == SCALE_DOWN) ? frame->header.bits_per_sample - m_bits_per_sample : (Mode == SCALE_UP) ? m_bits_per_sample - frame->header.bits_per_sample : 0; diff --git a/src/lib/util/flac.h b/src/lib/util/flac.h index c3fee4b574b..be3a0a8ac96 100644 --- a/src/lib/util/flac.h +++ b/src/lib/util/flac.h @@ -62,6 +62,10 @@ private: void init_common(); static FLAC__StreamEncoderWriteStatus write_callback_static(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data); FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame); + static FLAC__StreamEncoderSeekStatus seek_callback_static(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); + FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + static FLAC__StreamEncoderTellStatus tell_callback_static(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); // internal state FLAC__StreamEncoder * m_encoder; // actual encoder @@ -123,9 +127,9 @@ private: FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes); static void metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); static FLAC__StreamDecoderTellStatus tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - static FLAC__StreamDecoderWriteStatus write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); - template <DECODE_MODE Mode, bool SwapEndian> FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); + static FLAC__StreamDecoderWriteStatus write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data); + FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[]); + template <DECODE_MODE Mode, bool SwapEndian> FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 *const buffer[]); static void error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); // output state diff --git a/src/lib/util/harddisk.cpp b/src/lib/util/harddisk.cpp index 6eb12b38091..266e5d25a2b 100644 --- a/src/lib/util/harddisk.cpp +++ b/src/lib/util/harddisk.cpp @@ -16,6 +16,7 @@ #include "osdcore.h" #include <cstdlib> +#include <tuple> /*------------------------------------------------- @@ -118,7 +119,7 @@ bool hard_disk_file::read(uint32_t lbasector, void *buffer) size_t actual = 0; std::error_condition err = fhandle->seek(fileoffset + (lbasector * hdinfo.sectorbytes), SEEK_SET); if (!err) - err = fhandle->read(buffer, hdinfo.sectorbytes, actual); + std::tie(err, actual) = util::read(*fhandle, buffer, hdinfo.sectorbytes); return !err && (actual == hdinfo.sectorbytes); } } @@ -151,8 +152,8 @@ bool hard_disk_file::write(uint32_t lbasector, const void *buffer) size_t actual = 0; std::error_condition err = fhandle->seek(fileoffset + (lbasector * hdinfo.sectorbytes), SEEK_SET); if (!err) - err = fhandle->write(buffer, hdinfo.sectorbytes, actual); - return !err && (actual == hdinfo.sectorbytes); + std::tie(err, actual) = util::write(*fhandle, buffer, hdinfo.sectorbytes); + return !err; } } diff --git a/src/lib/util/hash.cpp b/src/lib/util/hash.cpp index 9100ff6abde..f2c528e9b22 100644 --- a/src/lib/util/hash.cpp +++ b/src/lib/util/hash.cpp @@ -410,14 +410,13 @@ std::error_condition hash_collection::compute(random_read &stream, uint64_t offs unsigned const chunk_length = std::min(length, sizeof(buffer)); // read one chunk - std::size_t bytes_read; - std::error_condition err = stream.read_at(offset, buffer, chunk_length, bytes_read); + auto const [err, bytes_read] = read_at(stream, offset, buffer, chunk_length); if (err) return err; if (!bytes_read) // EOF? break; offset += bytes_read; - length -= chunk_length; + length -= bytes_read; // append the chunk creator->append(buffer, bytes_read); diff --git a/src/lib/util/ioprocs.cpp b/src/lib/util/ioprocs.cpp index 0477f1efae1..687968f85ee 100644 --- a/src/lib/util/ioprocs.cpp +++ b/src/lib/util/ioprocs.cpp @@ -20,6 +20,7 @@ #include <cstring> #include <iterator> #include <limits> +#include <new> #include <type_traits> @@ -120,14 +121,14 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(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 + virtual std::error_condition read_some_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(); @@ -239,7 +240,7 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { if (m_dangling_write) { @@ -270,7 +271,7 @@ public: 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 + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -338,7 +339,7 @@ public: return std::error_condition(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { if (m_dangling_read) { @@ -361,7 +362,7 @@ public: 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 + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -409,7 +410,7 @@ public: set_filler(fill); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -473,7 +474,7 @@ public: 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 + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { actual = 0U; @@ -634,18 +635,12 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(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 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 count; - std::error_condition err = file().read(buffer, m_pointer, std::uint32_t(length), count); + std::error_condition err = file().read(buffer, m_pointer, chunk, count); if (!err) { m_pointer += count; @@ -658,18 +653,12 @@ public: return err; } - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_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 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 count; - std::error_condition err = file().read(buffer, offset, std::uint32_t(length), count); + std::error_condition err = file().read(buffer, offset, chunk, count); if (!err) actual = std::size_t(count); else @@ -696,48 +685,148 @@ public: return file().flush(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(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 count; + std::error_condition err = file().write(buffer, m_pointer, chunk, count); + if (!err) { - // 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; + actual = std::size_t(count); + m_pointer += count; } - return std::error_condition(); + else + { + actual = 0U; + } + return err; } - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_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(); + // 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 count; + std::error_condition err = file().write(buffer, offset, chunk, count); + if (!err) + actual = std::size_t(count); + else + actual = 0U; + return err; } }; } // anonymous namespace +// helper functions for common patterns + +std::pair<std::error_condition, std::size_t> read(read_stream &stream, void *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t count; + std::error_condition err = stream.read_some(buffer, length, count); + actual += count; + if (!err) + { + if (!count) + break; + } + else if (std::errc::interrupted != err) + { + return std::make_pair(err, actual); + } + buffer = reinterpret_cast<std::uint8_t *>(buffer) + count; + length -= count; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read(read_stream &stream, std::size_t length) noexcept +{ + std::unique_ptr<std::uint8_t []> buffer(new (std::nothrow) std::uint8_t [length]); + if (!buffer) + return std::make_tuple(std::errc::not_enough_memory, std::move(buffer), std::size_t(0)); + auto [err, actual] = read(stream, buffer.get(), length); + return std::make_tuple(err, std::move(buffer), actual); +} + +std::pair<std::error_condition, std::size_t> read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t count; + std::error_condition err = stream.read_some_at(offset, buffer, length, count); + actual += count; + if (!err) + { + if (!count) + break; + } + else if (std::errc::interrupted != err) + { + return std::make_pair(err, actual); + } + offset += count; + buffer = reinterpret_cast<std::uint8_t *>(buffer) + count; + length -= count; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept +{ + std::unique_ptr<std::uint8_t []> buffer(new (std::nothrow) std::uint8_t [length]); + if (!buffer) + return std::make_tuple(std::errc::not_enough_memory, std::move(buffer), std::size_t(0)); + auto [err, actual] = read_at(stream, offset, buffer.get(), length); + return std::make_tuple(err, std::move(buffer), actual); +} + +std::pair<std::error_condition, std::size_t> write(write_stream &stream, void const *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t written; + std::error_condition const err = stream.write_some(buffer, length, written); + assert(written || err || !length); + actual += written; + if (err && (std::errc::interrupted != err)) + return std::make_pair(err, actual); + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + +std::pair<std::error_condition, std::size_t> write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept +{ + std::size_t actual = 0; + do + { + std::size_t written; + std::error_condition const err = stream.write_some_at(offset, buffer, length, written); + assert(written || err || !length); + actual += written; + if (err && (std::errc::interrupted != err)) + return std::make_pair(err, actual); + offset += written; + buffer = reinterpret_cast<std::uint8_t const *>(buffer) + written; + length -= written; + } + while (length); + return std::make_pair(std::error_condition(), actual); +} + + // creating RAM read adapters random_read::ptr ram_read(void const *data, std::size_t size) noexcept diff --git a/src/lib/util/ioprocs.h b/src/lib/util/ioprocs.h index efe0a231a11..9e2c29d2a14 100644 --- a/src/lib/util/ioprocs.h +++ b/src/lib/util/ioprocs.h @@ -19,6 +19,8 @@ #include <cstdlib> #include <memory> #include <system_error> +#include <tuple> +#include <utility> // FIXME: make a proper place for OSD forward declarations @@ -56,7 +58,7 @@ public: /// \param [out] actual Number of bytes actually read. Will always /// be less than or equal to the requested length. /// \return An error condition if reading stopped due to an error. - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -100,7 +102,7 @@ public: /// \param [out] actual Number of bytes actually written. Will /// always be less than or equal to the requested length. /// \return An error condition if writing stopped due to an error. - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -184,7 +186,7 @@ public: /// be less than or equal to the requested length. /// \return An error condition if seeking failed or reading stopped /// due to an error. - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -214,7 +216,7 @@ public: /// always be less than or equal to the requested length. /// \return An error condition if seeking failed or writing stopped /// due to an error. - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -229,6 +231,123 @@ public: using ptr = std::unique_ptr<random_read_write>; }; + +/// \brief Read from the current position in the stream +/// +/// Reads up to the specified number of bytes from the stream into the +/// supplied buffer, continuing if interrupted by asynchronous signals. +/// May read less than the requested number of bytes if the end of the +/// stream is reached or an error occurs. If the stream supports +/// seeking, reading starts at the current position in the stream, and +/// the current position is incremented by the number of bytes read. +/// The operation may not be atomic if it is interrupted before the +/// requested number of bytes is read. +/// \param [in] stream The stream to read from. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A pair containing an error condition if reading stopped due +/// to an error, and the actual number of bytes read. +std::pair<std::error_condition, std::size_t> read(read_stream &stream, void *buffer, std::size_t length) noexcept; + +/// \brief Allocate memory and read from the current position in the +/// stream +/// +/// Allocates the specified number of bytes and then reads up to that +/// number of bytes from the stream into the newly allocated buffer, +/// continuing if interrupted by asynchronous signals. May read less +/// than the requested number of bytes if the end of the stream is +/// reached or an error occurs. If the stream supports seeking, +/// reading starts at the current position in the stream, and the +/// current position is incremented by the number of bytes read. The +/// operation may not be atomic if it is interrupted before the +/// requested number of bytes is read. No data will be read if +/// allocation fails. +/// \param [in] stream The stream to read from. +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A tuple containing an error condition if allocation failed +/// or reading stopped due to an error, the allocated buffer, and the +/// actual number of bytes read. +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read(read_stream &stream, std::size_t length) noexcept; + +/// \brief Read from the specified position +/// +/// Reads up to the specified number of bytes from the stream into the +/// supplied buffer, continuing if interrupted by asynchronous signals. +/// May read less than the requested number of bytes if the end of the +/// stream is reached or an error occurs. If seeking is supported, +/// reading starts at the specified position and the current position is +/// unaffected. The operation may not be atomic if it is interrupted +/// before the requested number of bytes is read. +/// \param [in] stream The stream to read from. +/// \param [in] offset The position to start reading from, specified as +/// a number of bytes from the beginning of the stream. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A pair containing an error condition if reading stopped due +/// to an error, and the actual number of bytes read. +std::pair<std::error_condition, std::size_t> read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept; + +/// \brief Allocate memory and read from the specified position +/// +/// Allocates the specified number of bytes and then reads up to that +/// number of bytes from the stream into the newly allocated buffer, +/// continuing if interrupted by asynchronous signals. May read less +/// than the requested number of bytes if the end of the stream is +/// reached or an error occurs. If seeking is supported, reading +/// starts at the specified position and the current position is +/// unaffected. The operation may not be atomic if it is interrupted +/// before the requested number of bytes is read. No data will be read +/// if allocation fails. +/// \param [in] stream The stream to read from. +/// \param [in] offset The position to start reading from, specified as +/// a number of bytes from the beginning of the stream. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A tuple containing an error condition if allocation failed +/// or reading stopped due to an error, the allocated buffer, and the +/// actual number of bytes read. +std::tuple<std::error_condition, std::unique_ptr<std::uint8_t []>, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept; + +/// \brief Write at the current position in the stream +/// +/// Writes up to the specified number of bytes from the supplied +/// buffer to the stream, continuing if interrupted by asynchronous +/// signals. May write less than the requested number of bytes if an +/// error occurs. If the stream supports seeking, writing starts at the +/// current position in the stream, and the current position is +/// incremented by the number of bytes written. The operation may not +/// be atomic if it is interrupted before the requested number of bytes +/// is written. +/// \param [in] stream The stream to write to. +/// \param [in] buffer Buffer containing the data to write. Must +/// contain at least the specified number of bytes. +/// \param [in] length Number of bytes to write. +/// \return A pair containing an error condition if writing stopped due +/// to an error, and the actual number of bytes written. +std::pair<std::error_condition, std::size_t> write(write_stream &stream, void const *buffer, std::size_t length) noexcept; + +/// \brief Write at specified position +/// +/// Writes up to the specified number of bytes from the supplied buffer, +/// continuing if interrupted by asynchronous signals. If seeking is +/// supported, writing starts at the specified position and the current +/// position is unaffected. May write less than the requested number +/// of bytes if an error occurs. The operation may not be atomic if it +/// is interrupted before the requested number of bytes is written. +/// \param [in] stream The stream to write to. +/// \param [in] offset The position to start writing at, specified as a +/// number of bytes from the beginning of the stream. +/// \param [in] buffer Buffer containing the data to write. Must +/// contain at least the specified number of bytes. +/// \param [in] length Number of bytes to write. +/// \return A pair containing an error condition if writing stopped due +/// to an error, and the actual number of bytes written. +std::pair<std::error_condition, std::size_t> write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept; + /// \} diff --git a/src/lib/util/ioprocsfill.h b/src/lib/util/ioprocsfill.h index e49b10687f0..7179d61852c 100644 --- a/src/lib/util/ioprocsfill.h +++ b/src/lib/util/ioprocsfill.h @@ -45,9 +45,21 @@ class read_stream_fill_wrapper : public Base, public virtual fill_wrapper_base<D public: using Base::Base; - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { - std::error_condition err = Base::read(buffer, length, actual); + // not atomic with respect to other read/write calls + actual = 0U; + std::error_condition err; + std::size_t chunk; + do + { + err = Base::read_some( + reinterpret_cast<std::uint8_t *>(buffer) + actual, + length - actual, + chunk); + actual += chunk; + } + while ((length > actual) && ((!err && chunk) || (std::errc::interrupted == err))); assert(length >= actual); std::fill( reinterpret_cast<std::uint8_t *>(buffer) + actual, @@ -64,9 +76,23 @@ class random_read_fill_wrapper : public read_stream_fill_wrapper<Base, DefaultFi 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 + virtual std::error_condition read_some_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); + // not atomic with respect to other read/write calls + actual = 0U; + std::error_condition err; + std::size_t chunk; + do + { + err = Base::read_some_at( + offset, + reinterpret_cast<std::uint8_t *>(buffer) + actual, + length - actual, + chunk); + offset += chunk; + actual += chunk; + } + while ((length > actual) && ((!err && chunk) || (std::errc::interrupted == err))); assert(length >= actual); std::fill( reinterpret_cast<std::uint8_t *>(buffer) + actual, @@ -83,8 +109,9 @@ class random_write_fill_wrapper : public Base, public virtual fill_wrapper_base< public: using Base::Base; - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { + // not atomic with respect to other read/write calls std::error_condition err; actual = 0U; @@ -108,23 +135,22 @@ public: 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; + std::size_t filled; + err = Base::write_some_at(current, fill_buffer, chunk, filled); + current += filled; + unfilled -= filled; + if (err && (std::errc::interrupted != err)) return err; - } - current += chunk; - unfilled -= chunk; } while (unfilled); } - return Base::write(buffer, length, actual); + return Base::write_some(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 + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { + // not atomic with respect to other read/write calls std::error_condition err; std::uint64_t current; err = Base::length(current); @@ -139,18 +165,19 @@ public: 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; + std::size_t filled; + err = Base::write_some_at(current, fill_buffer, chunk, filled); + current += filled; + unfilled -= filled; } - while (unfilled && !err); + while (unfilled && (!err || (std::errc::interrupted == err))); } if (err) { actual = 0U; return err; } - return Base::write_at(offset, buffer, length, actual); + return Base::write_some_at(offset, buffer, length, actual); } }; diff --git a/src/lib/util/ioprocsfilter.cpp b/src/lib/util/ioprocsfilter.cpp index 68b9c90d018..b8d4cc3e786 100644 --- a/src/lib/util/ioprocsfilter.cpp +++ b/src/lib/util/ioprocsfilter.cpp @@ -21,6 +21,7 @@ #include <cstdint> #include <limits> #include <system_error> +#include <tuple> #include <type_traits> #include <utility> @@ -372,9 +373,9 @@ class read_stream_proxy : public virtual read_stream, public T public: using T::T; - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { - return this->object().read(buffer, length, actual); + return this->object().read_some(buffer, length, actual); } }; @@ -397,9 +398,9 @@ public: return this->object().flush(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { - return this->object().write(buffer, length, actual); + return this->object().write_some(buffer, length, actual); } }; @@ -437,9 +438,9 @@ class random_read_proxy : public virtual random_read, public read_stream_proxy<T public: using read_stream_proxy<T>::read_stream_proxy; - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept override { - return this->object().read_at(offset, buffer, length, actual); + return this->object().read_some_at(offset, buffer, length, actual); } }; @@ -452,9 +453,9 @@ class random_write_proxy : public virtual random_write, public write_stream_prox public: using write_stream_proxy<T>::write_stream_proxy; - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept override { - return this->object().write_at(offset, buffer, length, actual); + return this->object().write_some_at(offset, buffer, length, actual); } }; @@ -487,7 +488,7 @@ public: { } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept override { std::error_condition err; actual = 0U; @@ -504,7 +505,7 @@ public: { auto const space = get_unfilled_input(); std::size_t filled; - err = this->object().read(space.first, space.second, filled); + std::tie(err, filled) = read(this->object(), space.first, space.second); add_input(filled); short_input = space.second > filled; } @@ -598,8 +599,7 @@ public: auto const output = get_output(); if (output.second) { - std::size_t written; - std::error_condition err = object().write(output.first, output.second, written); + auto const [err, written] = write(object(), output.first, output.second); consume_output(written); if (err) { @@ -611,7 +611,7 @@ public: return object().flush(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept override { std::error_condition err; actual = 0U; @@ -651,7 +651,7 @@ private: { auto const output = get_output(); std::size_t written; - std::error_condition err = object().write(output.first, output.second, written); + std::error_condition const err = object().write_some(output.first, output.second, written); consume_output(written); return err; } diff --git a/src/lib/util/ioprocsvec.h b/src/lib/util/ioprocsvec.h index d3c1c7fe01b..e66000b5729 100644 --- a/src/lib/util/ioprocsvec.h +++ b/src/lib/util/ioprocsvec.h @@ -90,14 +90,14 @@ public: return std::error_condition(); } - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition read_some(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 + virtual std::error_condition read_some_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(); @@ -113,14 +113,14 @@ public: return std::error_condition(); } - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept override + virtual std::error_condition write_some(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 + virtual std::error_condition write_some_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); } diff --git a/src/lib/util/jedparse.cpp b/src/lib/util/jedparse.cpp index 5915886b1a6..b347a2dd2b5 100644 --- a/src/lib/util/jedparse.cpp +++ b/src/lib/util/jedparse.cpp @@ -24,6 +24,7 @@ #include <cstdlib> #include <cstring> #include <cctype> +#include <tuple> @@ -194,7 +195,6 @@ static void process_field(jed_data *data, const uint8_t *cursrc, const uint8_t * int jed_parse(util::random_read &src, jed_data *result) { jed_parse_info pinfo; - int i; std::size_t actual; std::error_condition err; @@ -206,7 +206,7 @@ int jed_parse(util::random_read &src, jed_data *result) uint8_t ch; do { - err = src.read(&ch, 1, actual); + std::tie(err, actual) = read(src, &ch, 1); if (err) { if (LOG_PARSE) printf("Read error searching for JED start marker\n"); @@ -225,7 +225,7 @@ int jed_parse(util::random_read &src, jed_data *result) uint16_t checksum = ch; do { - err = src.read(&ch, 1, actual); + std::tie(err, actual) = read(src, &ch, 1); if (err) { if (LOG_PARSE) printf("Read error searching for JED end marker\n"); @@ -261,7 +261,8 @@ int jed_parse(util::random_read &src, jed_data *result) /* see if there is a transmission checksum at the end */ uint8_t sumbuf[4]; - if (!src.read(&sumbuf[0], 4, actual) && actual == 4 && ishex(sumbuf[0]) && ishex(sumbuf[1]) && ishex(sumbuf[2]) && ishex(sumbuf[3])) + std::tie(err, actual) = read(src, &sumbuf[0], 4); + if (!err && (actual == 4) && ishex(sumbuf[0]) && ishex(sumbuf[1]) && ishex(sumbuf[2]) && ishex(sumbuf[3])) { uint16_t dessum = (hexval(sumbuf[0]) << 12) | (hexval(sumbuf[1]) << 8) | (hexval(sumbuf[2]) << 4) | hexval(sumbuf[3] << 0); if (dessum != 0 && dessum != checksum) @@ -281,7 +282,8 @@ int jed_parse(util::random_read &src, jed_data *result) } } auto srcdata = std::make_unique<uint8_t[]>(endpos - startpos); - if (src.read(&srcdata[0], endpos - startpos, actual) || actual != endpos - startpos) + std::tie(err, actual) = read(src, &srcdata[0], endpos - startpos); + if (err || ((endpos - startpos) != actual)) { if (LOG_PARSE) printf("Error reading JED data\n"); return JEDERR_INVALID_DATA; @@ -325,7 +327,7 @@ int jed_parse(util::random_read &src, jed_data *result) /* validate the checksum */ checksum = 0; - for (i = 0; i < (result->numfuses + 7) / 8; i++) + for (int i = 0; i < ((result->numfuses + 7) / 8); i++) checksum += result->fusemap[i]; if (pinfo.checksum != 0 && checksum != pinfo.checksum) { @@ -441,13 +443,16 @@ size_t jed_output(const jed_data *data, void *result, size_t length) int jedbin_parse(util::read_stream &src, jed_data *result) { + std::error_condition err; + std::size_t actual; + /* initialize the output */ memset(result, 0, sizeof(*result)); /* need at least 4 bytes */ uint8_t buf[4]; - std::size_t actual; - if (src.read(&buf[0], 4, actual) || actual != 4) + std::tie(err, actual) = read(src, &buf[0], 4); + if (err || (4 != actual)) return JEDERR_INVALID_DATA; /* first unpack the number of fuses */ @@ -457,7 +462,8 @@ int jedbin_parse(util::read_stream &src, jed_data *result) /* now make sure we have enough data in the source */ /* copy in the data */ - if (src.read(result->fusemap, (result->numfuses + 7) / 8, actual) || actual != (result->numfuses + 7) / 8) + std::tie(err, actual) = read(src, result->fusemap, (result->numfuses + 7) / 8); + if (err || (((result->numfuses + 7) / 8) != actual)) return JEDERR_INVALID_DATA; return JEDERR_NONE; } diff --git a/src/lib/util/language.cpp b/src/lib/util/language.cpp index 3a00fe80ad7..50b518acd1b 100644 --- a/src/lib/util/language.cpp +++ b/src/lib/util/language.cpp @@ -61,11 +61,10 @@ void load_translation(random_read &file) return; } - std::size_t read; - file.read(translation_data.get(), size, read); - if (read != size) + auto const [err, actual] = read(file, translation_data.get(), size); + if (err || (actual != size)) { - osd_printf_error("Error reading translation file: requested %u bytes but got %u bytes\n", size, read); + osd_printf_error("Error reading translation file: requested %u bytes but got %u bytes\n", size, actual); translation_data.reset(); return; } diff --git a/src/lib/util/mfpresolve.cpp b/src/lib/util/mfpresolve.cpp new file mode 100644 index 00000000000..c7b9c58fde2 --- /dev/null +++ b/src/lib/util/mfpresolve.cpp @@ -0,0 +1,431 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + mfpresolve.h + + Helpers for resolving member function pointers to entry points. + +***************************************************************************/ + +#include "mfpresolve.h" + +#include "osdcomm.h" + +#include <cstdio> + + +//************************************************************************** +// MACROS +//************************************************************************** + +#if defined(MAME_DELEGATE_LOG_ADJ) + #define LOG(...) printf(__VA_ARGS__) +#else + #define LOG(...) do { if (false) printf(__VA_ARGS__); } while (false) +#endif + + + +namespace util::detail { + +std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_itanium( + std::uintptr_t function, + std::ptrdiff_t delta, + void const *object) noexcept +{ + // apply the "this" delta to the object first - the value is shifted to the left one bit position for the ARM-like variant + LOG("Input this=%p ptr=%p adj=%ld ", object, reinterpret_cast<void const *>(function), long(delta)); + constexpr int deltashift = (MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0; + object = reinterpret_cast<std::uint8_t const *>(object) + (delta >> deltashift); + LOG("Calculated this=%p ", object); + + // test the virtual member function flag - it's the low bit of either the ptr or adj field, depending on the variant + if ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? !(delta & 1) : !(function & 1)) + { + // conventional function pointer + LOG("ptr=%p\n", reinterpret_cast<void const *>(function)); + return std::make_pair(function, std::uintptr_t(object)); + } + else + { + // byte index into the vtable to the function + auto const vtable_ptr = *reinterpret_cast<std::uint8_t const *const *>(object) + function - ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 0 : 1); + std::uintptr_t result; + if (MAME_ABI_CXX_VTABLE_FNDESC) + result = std::uintptr_t(vtable_ptr); + else + result = *reinterpret_cast<std::uintptr_t const *>(vtable_ptr); + LOG("ptr=%p (vtable)\n", reinterpret_cast<void const *>(result)); + return std::make_pair(result, std::uintptr_t(object)); + } +} + + +std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_itanium( + std::uintptr_t function, + std::ptrdiff_t delta) noexcept +{ + constexpr uintptr_t funcmask = ~uintptr_t((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 0 : 1); + constexpr int deltashift = (MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0; + return std::make_tuple( + function & funcmask, + delta >> deltashift, + (MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? (delta & 1) : (function & 1)); +} + + +std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_msvc( + void const *funcptr, + std::size_t size, + void const *object) noexcept +{ + mfp_msvc_unknown_equiv const *unknown; + assert(sizeof(*unknown) >= size); + unknown = reinterpret_cast<mfp_msvc_unknown_equiv const *>(funcptr); + + LOG("Input this=%p ", object); + if (sizeof(mfp_msvc_single_equiv) < size) + LOG("thisdelta=%d ", unknown->delta); + if (sizeof(mfp_msvc_unknown_equiv) == size) + LOG("vptrdelta=%d vindex=%d ", unknown->voffset, unknown->vindex); + auto byteptr = reinterpret_cast<std::uint8_t const *>(object); + + // test for pointer to member function cast across virtual inheritance relationship + if ((sizeof(mfp_msvc_unknown_equiv) == size) && unknown->vindex) + { + // add offset from "this" pointer to location of vptr, and add offset to virtual base from vtable + byteptr += unknown->voffset; + auto const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr); + byteptr += *reinterpret_cast<int const *>(vptr + unknown->vindex); + } + + // add "this" pointer displacement if present in the pointer to member function + if (sizeof(mfp_msvc_single_equiv) < size) + byteptr += unknown->delta; + LOG("Calculated this=%p\n", reinterpret_cast<void const *>(byteptr)); + + // walk past recognisable thunks + return std::make_pair(bypass_member_function_thunks(unknown->entrypoint, byteptr), std::uintptr_t(byteptr)); +} + + +std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_msvc( + void const *funcptr, + std::size_t size) noexcept +{ + mfp_msvc_unknown_equiv const *unknown; + assert(sizeof(*unknown) >= size); + unknown = reinterpret_cast<mfp_msvc_unknown_equiv const *>(funcptr); + + // no way to represent pointer to member function cast across virtual inheritance relationship + if ((sizeof(mfp_msvc_unknown_equiv) == size) && unknown->vindex) + return std::make_tuple(std::uintptr_t(static_cast<void (*)()>(nullptr)), std::ptrdiff_t(0), false); + + auto const [function, is_virtual] = bypass_member_function_thunks(unknown->entrypoint); + return std::make_tuple( + function, + (sizeof(mfp_msvc_single_equiv) < size) ? unknown->delta : 0, + is_virtual); +} + + +std::uintptr_t bypass_member_function_thunks( + std::uintptr_t entrypoint, + void const *object) noexcept +{ +#if defined(__x86_64__) || defined(_M_X64) + std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(entrypoint); + while (true) + { + // Assumes Windows calling convention, and doesn't consider that + // the "this" pointer could be in RDX if RCX is a pointer to + // space for an oversize scalar result. Since the result area + // is uninitialised on entry, you won't see something that looks + // like a vtable dispatch through RCX in this case - it won't + // behave badly, it just won't bypass virtual call thunks in the + // rare situations where the return type is an oversize scalar. + if (0xe9 == func[0]) + { + // relative jump with 32-bit displacement (typically a resolved PLT entry) + LOG("Found relative jump at %p ", func); + func += std::ptrdiff_t(5) + *reinterpret_cast<std::int32_t const *>(func + 1); + LOG("redirecting to %p\n", func); + continue; + } + else if (object && (0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2])) + { + if ((0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) + { + // MSVC virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + if (0x20 == func[4]) // no displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr); + else if (0x60 == func[4]) // 8-bit displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); + else // 32-bit displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x48 == func[3]) && (0x8b == func[4])) + { + // clang virtual function call thunk - mov rax,QWORD PTR [rcx] ; mov rax,QWORD PTR [rax+...] ; jmp rax + if ((0x00 == func[5]) && (0x48 == func[6]) && (0xff == func[7]) && (0xe0 == func[8])) + { + // no displacement + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + func = *reinterpret_cast<std::uint8_t const *const *>(vptr); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x40 == func[5]) && (0x48 == func[7]) && (0xff == func[8]) && (0xe0 == func[9])) + { + // 8-bit displacement + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 6)); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x80 == func[5]) && (0x48 == func[10]) && (0xff == func[11]) && (0xe0 == func[12])) + { + // 32-bit displacement + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 6)); + LOG("redirecting to %p\n", func); + continue; + } + } + } + + // clang uses unoptimised thunks if optimisation is disabled + // Without optimisation, clang produces thunks like: + // 50 push rax + // 48 89 0c 24 mov QWORD PTR [rsp],rcx + // 48 8b 0c 24 mov rcx,QWORD PTR [rsp] + // 48 8b 01 mov rax,QWORD PTR [rcx] + // 48 8b 80 xx xx xx xx mov rax,QWORD PTR [rax+...] + // 41 5a pop r10 + // 48 ff e0 jmp rax + // Trying to decode these thunks likely isn't worth the effort. + // Chasing performance in unoptimised builds isn't very useful, + // and the format of these thunks may be fragile. + + // not something we can easily bypass + break; + } + return std::uintptr_t(func); +#elif defined(__aarch64__) || defined(_M_ARM64) + std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(entrypoint); + auto const fetch = [&func] (auto offset) { return little_endianize_int32(func[offset]); }; + while (true) + { + if ((0x90000010 == (fetch(0) & 0x9f00001f)) && (0x91000210 == (fetch(1) & 0xffc003ff)) && (0xd61f0200 == fetch(2))) + { + // page-relative jump with +/-4GB reach - adrp xip0,... ; add xip0,xip0,#... ; br xip0 + LOG("Found page-relative jump at %p ", func); + std::int64_t const page = + (std::uint64_t(fetch(0) & 0x60000000) >> 17) | + (std::uint64_t(fetch(0) & 0x00ffffe0) << 9) | + ((fetch(0) & 0x00800000) ? (~std::uint64_t(0) << 33) : 0); + std::uint32_t const offset = (fetch(1) & 0x003ffc00) >> 10; + func = reinterpret_cast<std::uint32_t const *>(((std::uintptr_t(func) + page) & (~std::uintptr_t(0) << 12)) + offset); + LOG("redirecting to %p\n", func); + } + else if (object && (0xf9400010 == fetch(0)) && (0xf9400210 == (fetch(1) & 0xffc003ff)) && (0xd61f0200 == fetch(2))) + { + // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0 + LOG("Found virtual member function thunk at %p ", func); + auto const vptr = *reinterpret_cast<std::uint32_t const *const *const *>(object); + func = vptr[(fetch(1) & 0x003ffc00) >> 10]; + LOG("redirecting to %p\n", func); + } + else + { + // not something we can easily bypass + break; + } + + // clang uses horribly sub-optimal thunks for AArch64 + // Without optimisation, clang produces thunks like: + // d10143ff sub sp,sp,#80 + // f90027e7 str x7,[sp,#72] + // f90023e6 str x6,[sp,#64] + // f9001fe5 str x5,[sp,#56] + // f9001be4 str x4,[sp,#48] + // f90017e3 str x3,[sp,#40] + // f90013e2 str x2,[sp,#32] + // f9000fe1 str x1,[sp,#24] + // f90007e0 str x0,[sp,#8] + // f94007e0 ldr x0,[sp,#8] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910143ff add sp,sp,#80 + // d61f0120 br x9 + // With optimisation, clang produces thunks like: + // d10103ff sub sp,sp,#64 + // a9008be1 stp x1,x2,[sp,#8] + // a90193e3 stp x3,x4,[sp,#24] + // a9029be5 stp x5,x6,[sp,#40] + // f9001fe7 str x7,[sp,#56] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910103ff add sp,sp,#64 + // d61f0120 br x9 + // It's more effort than it's worth to try decoding these + // thunks. + + } + return std::uintptr_t(func); +#else + return entrypoint; +#endif +} + + +std::pair<std::uintptr_t, bool> bypass_member_function_thunks( + std::uintptr_t entrypoint) noexcept +{ +#if defined(__x86_64__) || defined(_M_X64) + std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(entrypoint); + while (true) + { + // Assumes Windows calling convention, and doesn't consider that + // the "this" pointer could be in RDX if RCX is a pointer to + // space for an oversize scalar result. Since the result area + // is uninitialised on entry, you won't see something that looks + // like a vtable dispatch through RCX in this case - it won't + // behave badly, it just won't bypass virtual call thunks in the + // rare situations where the return type is an oversize scalar. + if (0xe9 == func[0]) + { + // relative jump with 32-bit displacement (typically a resolved PLT entry) + LOG("Found relative jump at %p ", func); + func += std::ptrdiff_t(5) + *reinterpret_cast<std::int32_t const *>(func + 1); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2])) + { + if ((0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) + { + // MSVC virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] + LOG("Found virtual member function thunk at %p\n", func); + if (0x20 == func[4]) // no displacement + return std::make_pair(std::uintptr_t(0), true); + else if (0x60 == func[4]) // 8-bit displacement + return std::make_pair(std::uintptr_t(*reinterpret_cast<std::int8_t const *>(func + 5)), true); + else // 32-bit displacement + return std::make_pair(std::uintptr_t(*reinterpret_cast<std::int32_t const *>(func + 5)), true); + } + else if ((0x48 == func[3]) && (0x8b == func[4])) + { + // clang virtual function call thunk - mov rax,QWORD PTR [rcx] ; mov rax,QWORD PTR [rax+...] ; jmp rax + if ((0x00 == func[5]) && (0x48 == func[6]) && (0xff == func[7]) && (0xe0 == func[8])) + { + // no displacement + LOG("Found virtual member function thunk at %p\n", func); + return std::make_pair(std::uintptr_t(0), true); + } + else if ((0x40 == func[5]) && (0x48 == func[7]) && (0xff == func[8]) && (0xe0 == func[9])) + { + // 8-bit displacement + LOG("Found virtual member function thunk at %p\n", func); + return std::make_pair(std::uintptr_t(*reinterpret_cast<std::int8_t const *>(func + 6)), true); + } + else if ((0x80 == func[5]) && (0x48 == func[10]) && (0xff == func[11]) && (0xe0 == func[12])) + { + // 32-bit displacement + LOG("Found virtual member function thunk at %p\n", func); + return std::make_pair(std::uintptr_t(*reinterpret_cast<std::int32_t const *>(func + 6)), true); + } + } + } + + // clang uses unoptimised thunks if optimisation is disabled + // Without optimisation, clang produces thunks like: + // 50 push rax + // 48 89 0c 24 mov QWORD PTR [rsp],rcx + // 48 8b 0c 24 mov rcx,QWORD PTR [rsp] + // 48 8b 01 mov rax,QWORD PTR [rcx] + // 48 8b 80 xx xx xx xx mov rax,QWORD PTR [rax+...] + // 41 5a pop r10 + // 48 ff e0 jmp rax + // Trying to decode these thunks likely isn't worth the effort. + // Chasing performance in unoptimised builds isn't very useful, + // and the format of these thunks may be fragile. + + // not something we can easily bypass + break; + } + return std::make_pair(std::uintptr_t(func), false); +#elif defined(__aarch64__) || defined(_M_ARM64) + std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(entrypoint); + auto const fetch = [&func] (auto offset) { return little_endianize_int32(func[offset]); }; + while (true) + { + if ((0x90000010 == (fetch(0) & 0x9f00001f)) && (0x91000210 == (fetch(1) & 0xffc003ff)) && (0xd61f0200 == fetch(2))) + { + // page-relative jump with +/-4GB reach - adrp xip0,... ; add xip0,xip0,#... ; br xip0 + LOG("Found page-relative jump at %p ", func); + std::int64_t const page = + (std::uint64_t(fetch(0) & 0x60000000) >> 17) | + (std::uint64_t(fetch(0) & 0x00ffffe0) << 9) | + ((fetch(0) & 0x00800000) ? (~std::uint64_t(0) << 33) : 0); + std::uint32_t const offset = (fetch(1) & 0x003ffc00) >> 10; + func = reinterpret_cast<std::uint32_t const *>(((std::uintptr_t(func) + page) & (~std::uintptr_t(0) << 12)) + offset); + LOG("redirecting to %p\n", func); + } + else if ((0xf9400010 == fetch(0)) && (0xf9400210 == (fetch(1) & 0xffc003ff)) && (0xd61f0200 == fetch(2))) + { + // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0 + LOG("Found virtual member function thunk at %p\n", func); + return std::make_pair(std::uintptr_t((fetch(1) & 0x003ffc00) >> (10 - 3)), true); + } + else + { + // not something we can easily bypass + break; + } + + // clang uses horribly sub-optimal thunks for AArch64 + // Without optimisation, clang produces thunks like: + // d10143ff sub sp,sp,#80 + // f90027e7 str x7,[sp,#72] + // f90023e6 str x6,[sp,#64] + // f9001fe5 str x5,[sp,#56] + // f9001be4 str x4,[sp,#48] + // f90017e3 str x3,[sp,#40] + // f90013e2 str x2,[sp,#32] + // f9000fe1 str x1,[sp,#24] + // f90007e0 str x0,[sp,#8] + // f94007e0 ldr x0,[sp,#8] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910143ff add sp,sp,#80 + // d61f0120 br x9 + // With optimisation, clang produces thunks like: + // d10103ff sub sp,sp,#64 + // a9008be1 stp x1,x2,[sp,#8] + // a90193e3 stp x3,x4,[sp,#24] + // a9029be5 stp x5,x6,[sp,#40] + // f9001fe7 str x7,[sp,#56] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910103ff add sp,sp,#64 + // d61f0120 br x9 + // It's more effort than it's worth to try decoding these + // thunks. + + } + return std::make_pair(std::uintptr_t(func), false); +#else + return std::make_pair(entrypoint, false); +#endif +} + +} // namespace util::detail diff --git a/src/lib/util/mfpresolve.h b/src/lib/util/mfpresolve.h new file mode 100644 index 00000000000..eb3fba2b85d --- /dev/null +++ b/src/lib/util/mfpresolve.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/*************************************************************************** + + mfpresolve.h + + Helpers for resolving member function pointers to entry points. + +***************************************************************************/ +#ifndef MAME_LIB_UTIL_MFPRESOLVE_H +#define MAME_LIB_UTIL_MFPRESOLVE_H + +#pragma once + +#include "abi.h" + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <tuple> +#include <utility> + + +namespace util { + +namespace detail { + +struct mfp_itanium_equiv +{ + std::uintptr_t function; + std::ptrdiff_t delta; + + constexpr std::ptrdiff_t this_delta() const noexcept { return delta >> ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0); } + constexpr bool is_virtual() const noexcept { return ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? delta : function) & 1; } +}; + +struct mfp_msvc_single_equiv { std::uintptr_t entrypoint; }; +struct mfp_msvc_multi_equiv { std::uintptr_t entrypoint; int delta; }; +struct mfp_msvc_virtual_equiv { std::uintptr_t entrypoint; int delta; int vindex; }; +struct mfp_msvc_unknown_equiv { std::uintptr_t entrypoint; int delta; int voffset; int vindex; }; + +std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_itanium(std::uintptr_t function, std::ptrdiff_t delta, void const *object) noexcept; +std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_itanium(std::uintptr_t function, std::ptrdiff_t delta) noexcept; +std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_msvc(void const *funcptr, std::size_t size, void const *object) noexcept; +std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_msvc(void const *funcptr, std::size_t size) noexcept; +std::uintptr_t bypass_member_function_thunks(std::uintptr_t entrypoint, void const *object) noexcept; +std::pair<std::uintptr_t, bool> bypass_member_function_thunks(std::uintptr_t entrypoint) noexcept; + +} // namespace detail + + +template <typename T, typename U> +inline T bypass_member_function_thunks(T entrypoint, U const *object) noexcept +{ + return reinterpret_cast<T>( + detail::bypass_member_function_thunks( + reinterpret_cast<std::uintptr_t>(entrypoint), + reinterpret_cast<void const *>(object))); +} + + +template <typename T, typename Ret, typename... Params> +inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...), T &object) noexcept +{ + if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM) + { + detail::mfp_itanium_equiv equiv; + assert(sizeof(function) == sizeof(equiv)); + *reinterpret_cast<decltype(function) *>(&equiv) = function; + return detail::resolve_member_function_itanium(equiv.function, equiv.delta, &object); + } + else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC) + { + return detail::resolve_member_function_msvc(&function, sizeof(function), &object); + } + else + { + return std::make_pair( + std::uintptr_t(static_cast<void (*)()>(nullptr)), + std::uintptr_t(static_cast<void *>(nullptr))); + } +} + + +template <typename T, typename Ret, typename... Params> +inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...) const, T const &object) noexcept +{ + if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM) + { + detail::mfp_itanium_equiv equiv; + assert(sizeof(function) == sizeof(equiv)); + *reinterpret_cast<decltype(function) *>(&equiv) = function; + return detail::resolve_member_function_itanium(equiv.function, equiv.delta, &object); + } + else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC) + { + return detail::resolve_member_function_msvc(&function, sizeof(function), &object); + } + else + { + return std::make_pair( + std::uintptr_t(static_cast<void (*)()>(nullptr)), + std::uintptr_t(static_cast<void *>(nullptr))); + } +} + + +template <typename T, typename Ret, typename... Params> +inline std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function(Ret (T::*function)(Params...)) noexcept +{ + if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM) + { + detail::mfp_itanium_equiv equiv; + assert(sizeof(function) == sizeof(equiv)); + *reinterpret_cast<decltype(function) *>(&equiv) = function; + return detail::resolve_member_function_itanium(equiv.function, equiv.delta); + } + else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC) + { + return detail::resolve_member_function_msvc(&function, sizeof(function)); + } + else + { + return std::make_tuple(std::uintptr_t(static_cast<void (*)()>(nullptr)), std::ptrdiff_t(0), false); + } +} + + +template <typename T, typename Ret, typename... Params> +inline std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function(Ret (T::*function)(Params...) const) noexcept +{ + if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM) + { + detail::mfp_itanium_equiv equiv; + assert(sizeof(function) == sizeof(equiv)); + *reinterpret_cast<decltype(function) *>(&equiv) = function; + return detail::resolve_member_function_itanium(equiv.function, equiv.delta); + } + else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC) + { + return detail::resolve_member_function_msvc(&function, sizeof(function)); + } + else + { + return std::make_tuple(std::uintptr_t(static_cast<void (*)()>(nullptr)), std::ptrdiff_t(0), false); + } +} + +} // namespace util + +#endif // MAME_LIB_UTIL_MFPRESOLVE_H diff --git a/src/lib/util/msdib.cpp b/src/lib/util/msdib.cpp index e70ba1b592a..bf33991f116 100644 --- a/src/lib/util/msdib.cpp +++ b/src/lib/util/msdib.cpp @@ -20,6 +20,7 @@ #include <cassert> #include <cstdlib> #include <cstring> +#include <tuple> #define LOG_GENERAL (1U << 0) @@ -127,11 +128,10 @@ std::uint8_t dib_splat_sample(std::uint8_t val, unsigned bits) noexcept msdib_error dib_read_file_header(read_stream &fp, std::uint32_t &filelen) noexcept { - std::size_t actual; - // the bitmap file header doesn't use natural alignment bitmap_file_header file_header; - if (fp.read(file_header, sizeof(file_header), actual) || (sizeof(file_header) != actual)) + auto const [err, actual] = read(fp, file_header, sizeof(file_header)); + if (err || (sizeof(file_header) != actual)) { LOG("Error reading DIB file header\n"); return msdib_error::FILE_TRUNCATED; @@ -167,6 +167,7 @@ msdib_error dib_read_bitmap_header( std::size_t &row_bytes, std::uint32_t length) noexcept { + std::error_condition err; std::size_t actual; // check that these things haven't been padded somehow @@ -178,7 +179,8 @@ msdib_error dib_read_bitmap_header( if (sizeof(header.core) > length) return msdib_error::FILE_TRUNCATED; std::memset(&header, 0, sizeof(header)); - if (fp.read(&header.core.size, sizeof(header.core.size), actual) || (sizeof(header.core.size) != actual)) + std::tie(err, actual) = read(fp, &header.core.size, sizeof(header.core.size)); + if (err || (sizeof(header.core.size) != actual)) { LOG("Error reading DIB header size (length %u)\n", length); return msdib_error::FILE_TRUNCATED; @@ -208,7 +210,8 @@ msdib_error dib_read_bitmap_header( { palette_bytes = 3U; std::uint32_t const header_read(std::min<std::uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size)); - if (fp.read(&header.core.width, header_read, actual) || (header_read != actual)) + std::tie(err, actual) = read(fp, &header.core.width, header_read); + if (err || (header_read != actual)) { LOG("Error reading DIB core header from image data (%u bytes)\n", length); return msdib_error::FILE_TRUNCATED; @@ -261,7 +264,8 @@ msdib_error dib_read_bitmap_header( { palette_bytes = 4U; std::uint32_t const header_read(std::min<std::uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size)); - if (fp.read(&header.info.width, header_read, actual) || (header_read != actual)) + std::tie(err, actual) = read(fp, &header.info.width, header_read); + if (err || (header_read != actual)) { LOG("Error reading DIB info header from image data (%u bytes)\n", length); return msdib_error::FILE_TRUNCATED; @@ -445,7 +449,6 @@ msdib_error msdib_read_bitmap(random_read &fp, bitmap_argb32 &bitmap) noexcept msdib_error msdib_read_bitmap_data(random_read &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight) noexcept { // read the bitmap header - std::size_t actual; bitmap_headers header; unsigned palette_bytes; bool indexed; @@ -492,7 +495,8 @@ msdib_error msdib_read_bitmap_data(random_read &fp, bitmap_argb32 &bitmap, std:: std::unique_ptr<std::uint8_t []> palette_data(new (std::nothrow) std::uint8_t [palette_size]); if (!palette_data) return msdib_error::OUT_OF_MEMORY; - if (fp.read(palette_data.get(), palette_size, actual) || (palette_size != actual)) + auto const [err, actual] = read(fp, palette_data.get(), palette_size); + if (err || (palette_size != actual)) { LOG("Error reading palette from DIB image data (%u bytes)\n", length); return msdib_error::FILE_TRUNCATED; @@ -575,7 +579,8 @@ msdib_error msdib_read_bitmap_data(random_read &fp, bitmap_argb32 &bitmap, std:: int const y_inc(top_down ? 1 : -1); for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc) { - if (fp.read(row_data.get(), row_bytes, actual) || (row_bytes != actual)) + auto const [err, actual] = read(fp, row_data.get(), row_bytes); + if (err || (row_bytes != actual)) { LOG("Error reading DIB row %d data from image data\n", i); return msdib_error::FILE_TRUNCATED; @@ -638,7 +643,8 @@ msdib_error msdib_read_bitmap_data(random_read &fp, bitmap_argb32 &bitmap, std:: { for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc) { - if (fp.read(row_data.get(), mask_row_bytes, actual) || (mask_row_bytes != actual)) + auto const [err, actual] = read(fp, row_data.get(), mask_row_bytes); + if (err || (mask_row_bytes != actual)) { LOG("Error reading DIB mask row %d data from image data\n", i); return msdib_error::FILE_TRUNCATED; diff --git a/src/lib/util/options.h b/src/lib/util/options.h index 99db519a5e5..8b85b9f58e6 100644 --- a/src/lib/util/options.h +++ b/src/lib/util/options.h @@ -12,6 +12,7 @@ #define MAME_LIB_UTIL_OPTIONS_H #include "strformat.h" +#include "utilfwd.h" #include <algorithm> #include <exception> @@ -43,7 +44,6 @@ const int OPTION_PRIORITY_MAXIMUM = 255; // maximum priority //************************************************************************** struct options_entry; -namespace util { class core_file; } // exception thrown by core_options when an illegal request is made class options_exception : public std::exception diff --git a/src/lib/util/plaparse.cpp b/src/lib/util/plaparse.cpp index 423939b41a8..9f4d1c0bc14 100644 --- a/src/lib/util/plaparse.cpp +++ b/src/lib/util/plaparse.cpp @@ -68,11 +68,14 @@ static uint32_t suck_number(util::random_read &src) uint32_t value = 0; // find first digit - uint8_t ch; - std::size_t actual; bool found = false; - while (!src.read(&ch, 1, actual) && actual == 1) + while (true) { + uint8_t ch; + auto const [err, actual] = read(src, &ch, 1); + if (err || (1 != actual)) + break; + // loop over and accumulate digits if (isdigit(ch)) { @@ -189,8 +192,8 @@ static bool process_terms(jed_data *data, util::random_read &src, uint8_t ch, pa curoutput = 0; } - std::size_t actual; - if (src.read(&ch, 1, actual)) + auto const [err, actual] = read(src, &ch, 1); + if (err) return false; if (actual != 1) return true; @@ -227,9 +230,11 @@ static bool process_field(jed_data *data, util::random_read &src, parse_info *pi int destptr = 0; uint8_t seek; - std::size_t actual; - while (!src.read(&seek, 1, actual) && actual == 1 && isalpha(seek)) + while (true) { + auto const [err, actual] = read(src, &seek, 1); + if (err || (actual != 1) || !isalpha(seek)) + break; dest[destptr++] = tolower(seek); if (destptr == sizeof(dest)) break; @@ -275,8 +280,11 @@ static bool process_field(jed_data *data, util::random_read &src, parse_info *pi // output polarity (optional) case KW_PHASE: if (LOG_PARSE) printf("Phase...\n"); - while (!src.read(&seek, 1, actual) && actual == 1 && !iscrlf(seek) && pinfo->xorptr < (JED_MAX_FUSES/2)) + while (true) { + auto const [err, actual] = read(src, &seek, 1); + if (err || (actual != 1) || iscrlf(seek) || (pinfo->xorptr >= (JED_MAX_FUSES / 2))) + break; if (seek == '0' || seek == '1') { // 0 is negative @@ -322,19 +330,23 @@ int pla_parse(util::random_read &src, jed_data *result) result->numfuses = 0; memset(result->fusemap, 0, sizeof(result->fusemap)); - uint8_t ch; - std::size_t actual; - while (!src.read(&ch, 1, actual) && actual == 1) + while (true) { + std::error_condition err; + size_t actual; + uint8_t ch; + std::tie(err, actual) = read(src, &ch, 1); + if (err || (actual != 1)) + break; switch (ch) { // comment line case '#': - while (!src.read(&ch, 1, actual) && actual == 1) + do { - if (iscrlf(ch)) - break; + std::tie(err, actual) = read(src, &ch, 1); } + while (!err && (actual == 1) && !iscrlf(ch)); break; // keyword diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp index 8e077f92114..ce28a866604 100644 --- a/src/lib/util/png.cpp +++ b/src/lib/util/png.cpp @@ -24,6 +24,7 @@ #include <cstdlib> #include <cstring> #include <new> +#include <tuple> namespace util { @@ -452,7 +453,7 @@ private: std::uint8_t tempbuff[4]; // fetch the length of this chunk - err = fp.read(tempbuff, 4, actual); + std::tie(err, actual) = read(fp, tempbuff, 4); if (err) return err; else if (4 != actual) @@ -460,7 +461,7 @@ private: length = fetch_32bit(tempbuff); // fetch the type of this chunk - err = fp.read(tempbuff, 4, actual); + std::tie(err, actual) = read(fp, tempbuff, 4); if (err) return err; else if (4 != actual) @@ -477,13 +478,8 @@ private: // read the chunk itself into an allocated memory buffer if (length) { - // allocate memory for this chunk - data.reset(new (std::nothrow) std::uint8_t [length]); - if (!data) - return std::errc::not_enough_memory; - - // read the data from the file - err = fp.read(data.get(), length, actual); + // allocate memory and read the data from the file + std::tie(err, data, actual) = read(fp, length); if (err) { data.reset(); @@ -500,7 +496,7 @@ private: } // read the CRC - err = fp.read(tempbuff, 4, actual); + std::tie(err, actual) = read(fp, tempbuff, 4); if (err) { data.reset(); @@ -789,8 +785,7 @@ public: std::uint8_t signature[sizeof(PNG_SIGNATURE)]; // read 8 bytes - std::size_t actual; - std::error_condition err = fp.read(signature, sizeof(signature), actual); + auto const [err, actual] = read(fp, signature, sizeof(signature)); if (err) return err; else if (sizeof(signature) != actual) @@ -941,7 +936,6 @@ std::error_condition png_info::add_text(std::string_view keyword, std::string_vi static std::error_condition write_chunk(write_stream &fp, const uint8_t *data, uint32_t type, uint32_t length) noexcept { std::error_condition err; - std::size_t written; std::uint8_t tempbuff[8]; std::uint32_t crc; @@ -951,30 +945,24 @@ static std::error_condition write_chunk(write_stream &fp, const uint8_t *data, u crc = crc32(0, tempbuff + 4, 4); // write that data - err = fp.write(tempbuff, 8, written); + std::tie(err, std::ignore) = write(fp, tempbuff, 8); if (err) return err; - else if (8 != written) - return std::errc::io_error; // append the actual data if (length > 0) { - err = fp.write(data, length, written); + std::tie(err, std::ignore) = write(fp, data, length); if (err) return err; - else if (length != written) - return std::errc::io_error; crc = crc32(crc, data, length); } // write the CRC put_32bit(tempbuff, crc); - err = fp.write(tempbuff, 4, written); + std::tie(err, std::ignore) = write(fp, tempbuff, 4); if (err) return err; - else if (4 != written) - return std::errc::io_error; return std::error_condition(); } @@ -993,7 +981,6 @@ static std::error_condition write_deflated_chunk(random_write &fp, uint8_t *data if (err) return err; - std::size_t written; std::uint8_t tempbuff[8192]; std::uint32_t zlength = 0; z_stream stream; @@ -1006,11 +993,9 @@ static std::error_condition write_deflated_chunk(random_write &fp, uint8_t *data crc = crc32(0, tempbuff + 4, 4); // write that data - err = fp.write(tempbuff, 8, written); + std::tie(err, std::ignore) = write(fp, tempbuff, 8); if (err) return err; - else if (8 != written) - return std::errc::io_error; // initialize the stream memset(&stream, 0, sizeof(stream)); @@ -1036,17 +1021,12 @@ static std::error_condition write_deflated_chunk(random_write &fp, uint8_t *data if (stream.avail_out < sizeof(tempbuff)) { int bytes = sizeof(tempbuff) - stream.avail_out; - err = fp.write(tempbuff, bytes, written); + std::tie(err, std::ignore) = write(fp, tempbuff, bytes); if (err) { deflateEnd(&stream); return err; } - else if (bytes != written) - { - deflateEnd(&stream); - return std::errc::io_error; - } crc = crc32(crc, tempbuff, bytes); zlength += bytes; } @@ -1079,22 +1059,18 @@ static std::error_condition write_deflated_chunk(random_write &fp, uint8_t *data // write the CRC put_32bit(tempbuff, crc); - err = fp.write(tempbuff, 4, written); + std::tie(err, std::ignore) = write(fp, tempbuff, 4); if (err) return err; - else if (4 != written) - return std::errc::io_error; // seek back and update the length err = fp.seek(lengthpos, SEEK_SET); if (err) return err; put_32bit(tempbuff + 0, zlength); - err = fp.write(tempbuff, 4, written); + std::tie(err, std::ignore) = write(fp, tempbuff, 4); if (err) return err; - else if (4 != written) - return std::errc::io_error; // return to the end return fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET); @@ -1326,12 +1302,9 @@ std::error_condition png_write_bitmap(random_write &fp, png_info *info, bitmap_t info = &pnginfo; // write the PNG signature - std::size_t written; - std::error_condition err = fp.write(PNG_SIGNATURE, sizeof(PNG_SIGNATURE), written); + auto const [err, written] = write(fp, PNG_SIGNATURE, sizeof(PNG_SIGNATURE)); if (err) return err; - else if (sizeof(PNG_SIGNATURE) != written) - return std::errc::io_error; // write the rest of the PNG data return write_png_stream(fp, *info, bitmap, palette_length, palette); @@ -1347,12 +1320,9 @@ std::error_condition png_write_bitmap(random_write &fp, png_info *info, bitmap_t std::error_condition mng_capture_start(random_write &fp, bitmap_t const &bitmap, unsigned rate) noexcept { - std::size_t written; - std::error_condition err = fp.write(MNG_Signature, 8, written); + auto const [err, written] = write(fp, MNG_Signature, 8); if (err) return err; - else if (8 != written) - return std::errc::io_error; uint8_t mhdr[28]; memset(mhdr, 0, 28); diff --git a/src/lib/util/server_http_impl.hpp b/src/lib/util/server_http_impl.hpp index e949e6b2483..7de440bce2c 100644 --- a/src/lib/util/server_http_impl.hpp +++ b/src/lib/util/server_http_impl.hpp @@ -63,10 +63,10 @@ namespace webpp { } } public: - virtual Response& status(int number) { m_ostream << statusToString(number); return *this; } - virtual void type(std::string str) { m_header << "Content-Type: "<< str << "\r\n"; } - virtual void send(std::string str) { m_ostream << m_header.str() << "Content-Length: " << str.length() << "\r\n\r\n" << str; } - virtual size_t size() const { return m_streambuf.size(); } + virtual Response& status(int number) override { m_ostream << statusToString(number); return *this; } + virtual void type(std::string str) override { m_header << "Content-Type: "<< str << "\r\n"; } + virtual void send(std::string str) override { m_ostream << m_header.str() << "Content-Length: " << str.length() << "\r\n\r\n" << str; } + virtual size_t size() const override { return m_streambuf.size(); } std::shared_ptr<socket_type> socket() { return m_socket; } /// If true, force server to close the connection after the response have been sent. diff --git a/src/lib/util/simh_tape_file.cpp b/src/lib/util/simh_tape_file.cpp index 4fe1af5ae88..ffd6a48aeb3 100644 --- a/src/lib/util/simh_tape_file.cpp +++ b/src/lib/util/simh_tape_file.cpp @@ -119,16 +119,14 @@ void simh_tape_file::raw_seek(const osd::u64 pos) const void simh_tape_file::raw_read(osd::u8 *const buf, const osd::u32 len) const { - size_t actual_len; - std::error_condition err = m_file.read(buf, len, actual_len); + auto const [err, actual_len] = read(m_file, buf, len); if (err || actual_len != len) // error: we failed to read expected number of bytes throw std::runtime_error(std::string("failed read: ") + (err ? err.message() : std::string("unexpected length"))); } void simh_tape_file::raw_write(const osd::u8 *const buf, const osd::u32 len) const { - size_t actual_len; - std::error_condition err = m_file.write(buf, len, actual_len); + auto const [err, actual_len] = write(m_file, buf, len); if (err || actual_len != len) // error: we failed to write expected number of bytes throw std::runtime_error(std::string("failed write: ") + (err ? err.message() : std::string("unexpected length"))); } diff --git a/src/lib/util/un7z.cpp b/src/lib/util/un7z.cpp index 362c95ee235..5ee97d62777 100644 --- a/src/lib/util/un7z.cpp +++ b/src/lib/util/un7z.cpp @@ -71,8 +71,7 @@ private: if (!size) return SZ_OK; - std::size_t read_length(0); - std::error_condition const err = file->read_at(currfpos, data, size, read_length); + auto const [err, read_length] = read_at(*file, currfpos, data, size); size = read_length; currfpos += read_length; diff --git a/src/lib/util/unzip.cpp b/src/lib/util/unzip.cpp index c1df469fed4..2ca8e722d25 100644 --- a/src/lib/util/unzip.cpp +++ b/src/lib/util/unzip.cpp @@ -154,8 +154,7 @@ public: while (cd_remaining) { 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); + auto const [filerr, read_length] = read_at(*m_file, m_ecd.cd_start_disk_offset + cd_offs, &m_cd[cd_offs], chunk); if (filerr) { osd_printf_error( @@ -914,7 +913,7 @@ std::error_condition zip_file_impl::decompress(void *buffer, std::size_t length) } // get the compressed data offset - std::uint64_t offset; + std::uint64_t offset = 0; auto const ziperr = get_compressed_data_offset(offset); if (ziperr) return ziperr; @@ -979,7 +978,7 @@ std::error_condition zip_file_impl::read_ecd() noexcept } // read in one buffers' worth of data - filerr = m_file->read_at(m_length - buflen, &buffer[0], buflen, read_length); + std::tie(filerr, read_length) = read_at(*m_file, m_length - buflen, &buffer[0], buflen); if (filerr) { osd_printf_error( @@ -1024,11 +1023,11 @@ std::error_condition zip_file_impl::read_ecd() noexcept } // try to read the ZIP64 ECD locator - filerr = m_file->read_at( + std::tie(filerr, read_length) = read_at( + *m_file, m_length - buflen + offset - ecd64_locator_reader::minimum_length(), &buffer[0], - ecd64_locator_reader::minimum_length(), - read_length); + ecd64_locator_reader::minimum_length()); if (filerr) { osd_printf_error( @@ -1058,7 +1057,7 @@ std::error_condition zip_file_impl::read_ecd() noexcept } // try to read the ZIP64 ECD - filerr = m_file->read_at(ecd64_loc_rd.ecd64_offset(), &buffer[0], ecd64_reader::minimum_length(), read_length); + std::tie(filerr, read_length) = read_at(*m_file, ecd64_loc_rd.ecd64_offset(), &buffer[0], ecd64_reader::minimum_length()); if (filerr) { osd_printf_error( @@ -1160,8 +1159,7 @@ std::error_condition zip_file_impl::get_compressed_data_offset(std::uint64_t &of return ziperr; // now go read the fixed-sized part of the local file header - 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); + auto const [filerr, read_length] = read_at(*m_file, m_header.local_header_offset, &m_buffer[0], local_file_header_reader::minimum_length()); if (filerr) { osd_printf_error( @@ -1205,8 +1203,7 @@ std::error_condition zip_file_impl::get_compressed_data_offset(std::uint64_t &of 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::size_t read_length(0); - std::error_condition const filerr = m_file->read_at(offset, buffer, m_header.compressed_length, read_length); + auto const [filerr, read_length] = read_at(*m_file, offset, buffer, m_header.compressed_length); if (filerr) { osd_printf_error( @@ -1277,12 +1274,11 @@ std::error_condition zip_file_impl::decompress_data_type_8(std::uint64_t offset, while (true) { // read in the next chunk of data - std::size_t read_length(0); - auto const filerr = m_file->read_at( + auto const [filerr, read_length] = read_at( + *m_file, offset, &m_buffer[0], - std::size_t(std::min<std::uint64_t>(input_remaining, m_buffer.size())), - read_length); + std::size_t(std::min<std::uint64_t>(input_remaining, m_buffer.size()))); if (filerr) { osd_printf_error( @@ -1393,7 +1389,7 @@ std::error_condition zip_file_impl::decompress_data_type_14(std::uint64_t offset m_header.file_name, m_filename); return archive_file::error::DECOMPRESS_ERROR; } - filerr = m_file->read_at(offset, &m_buffer[0], 4, read_length); + std::tie(filerr, read_length) = read_at(*m_file, offset, &m_buffer[0], 4); if (filerr) { osd_printf_error( @@ -1425,7 +1421,7 @@ std::error_condition zip_file_impl::decompress_data_type_14(std::uint64_t offset m_header.file_name, m_filename); return archive_file::error::DECOMPRESS_ERROR; } - filerr = m_file->read_at(offset, &m_buffer[0], props_size, read_length); + std::tie(filerr, read_length) = read_at(*m_file, offset, &m_buffer[0], props_size); if (filerr) { osd_printf_error( @@ -1472,11 +1468,11 @@ std::error_condition 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_at( + std::tie(filerr, read_length) = read_at( + *m_file, offset, &m_buffer[0], - std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size())), - read_length); + std::size_t((std::min<std::uint64_t>)(input_remaining, m_buffer.size()))); if (filerr) { osd_printf_error( @@ -1569,12 +1565,11 @@ std::error_condition zip_file_impl::decompress_data_type_93(std::uint64_t offset while (input_remaining && length) { // read in the next chunk of data - std::size_t read_length(0); - auto const filerr = m_file->read_at( + auto const [filerr, read_length] = read_at( + *m_file, offset, &m_buffer[0], - std::size_t(std::min<std::uint64_t>(input_remaining, m_buffer.size())), - read_length); + std::size_t(std::min<std::uint64_t>(input_remaining, m_buffer.size()))); if (filerr) { osd_printf_error( diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index 39604a29a87..db8d87930e2 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -41,14 +41,14 @@ constexpr unsigned TEMP_BUFFER_SIZE(4096U); void write_escaped(core_file &file, std::string const &str) { + // FIXME: check for errors std::string::size_type pos = 0; while ((str.size() > pos) && (std::string::npos != pos)) { std::string::size_type const found = str.find_first_of("\"&<>", pos); if (found != std::string::npos) { - std::size_t written; - file.write(&str[pos], found - pos, written); + write(file, &str[pos], found - pos); switch (str[found]) { case '"': file.puts("""); pos = found + 1; break; @@ -60,8 +60,7 @@ void write_escaped(core_file &file, std::string const &str) } else { - std::size_t written; - file.write(&str[pos], str.size() - pos, written); + write(file, &str[pos], str.size() - pos); pos = found; } } @@ -77,10 +76,12 @@ void write_escaped(core_file &file, std::string const &str) struct parse_info { + parse_info() { memset(&parser, 0, sizeof(parser)); } + XML_Parser parser; file::ptr rootnode; - data_node * curnode; - uint32_t flags; + data_node * curnode = nullptr; + uint32_t flags = 0; }; @@ -134,8 +135,7 @@ file::ptr file::read(read_stream &file, parse_options const *opts) char tempbuf[TEMP_BUFFER_SIZE]; // read as much as we can - size_t bytes; - file.read(tempbuf, sizeof(tempbuf), bytes); // TODO: better error handling + auto const [err, bytes] = util::read(file, tempbuf, sizeof(tempbuf)); // FIXME: better error handling done = !bytes; // parse the data @@ -815,7 +815,7 @@ std::string normalize_string(std::string_view string) static bool expat_setup_parser(parse_info &info, parse_options const *opts) { // setup info structure - memset(&info, 0, sizeof(info)); + info = parse_info(); if (opts != nullptr) { info.flags = opts->flags; |