summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats')
-rw-r--r--src/lib/formats/86f_dsk.cpp272
-rw-r--r--src/lib/formats/86f_dsk.h37
-rw-r--r--src/lib/formats/a26_cas.cpp2
-rw-r--r--src/lib/formats/abc800i_dsk.cpp5
-rw-r--r--src/lib/formats/ace_tap.cpp2
-rw-r--r--src/lib/formats/acorn_dsk.cpp88
-rw-r--r--src/lib/formats/aim_dsk.cpp4
-rw-r--r--src/lib/formats/all.cpp19
-rw-r--r--src/lib/formats/ami_dsk.cpp14
-rw-r--r--src/lib/formats/ap2_dsk.cpp562
-rw-r--r--src/lib/formats/ap2_dsk.h32
-rw-r--r--src/lib/formats/ap_dsk35.cpp62
-rw-r--r--src/lib/formats/apd_dsk.cpp12
-rw-r--r--src/lib/formats/apf_apt.cpp4
-rw-r--r--src/lib/formats/apridisk.cpp13
-rw-r--r--src/lib/formats/as_dsk.cpp250
-rw-r--r--src/lib/formats/as_dsk.h12
-rw-r--r--src/lib/formats/bk0010_dsk.cpp39
-rw-r--r--src/lib/formats/bk0010_dsk.h30
-rw-r--r--src/lib/formats/camplynx_cas.cpp2
-rw-r--r--src/lib/formats/cassimg.cpp54
-rw-r--r--src/lib/formats/cassimg.h2
-rw-r--r--src/lib/formats/cbm_crt.cpp23
-rw-r--r--src/lib/formats/cbm_tap.cpp2
-rw-r--r--src/lib/formats/ccvf_dsk.cpp12
-rw-r--r--src/lib/formats/cgen_cas.cpp2
-rw-r--r--src/lib/formats/concept_dsk.cpp6
-rw-r--r--src/lib/formats/coupedsk.cpp6
-rw-r--r--src/lib/formats/cp68_dsk.cpp14
-rw-r--r--src/lib/formats/cqm_dsk.cpp13
-rw-r--r--src/lib/formats/d64_dsk.cpp9
-rw-r--r--src/lib/formats/d88_dsk.cpp39
-rw-r--r--src/lib/formats/dcp_dsk.cpp14
-rw-r--r--src/lib/formats/dfi_dsk.cpp19
-rw-r--r--src/lib/formats/dim_dsk.cpp15
-rw-r--r--src/lib/formats/dip_dsk.cpp3
-rw-r--r--src/lib/formats/dmk_dsk.cpp138
-rw-r--r--src/lib/formats/ds9_dsk.cpp3
-rw-r--r--src/lib/formats/dsk_dsk.cpp23
-rw-r--r--src/lib/formats/dvk_mx_dsk.cpp145
-rw-r--r--src/lib/formats/dvk_mx_dsk.h13
-rw-r--r--src/lib/formats/esq16_dsk.cpp6
-rw-r--r--src/lib/formats/esq8_dsk.cpp6
-rw-r--r--src/lib/formats/fc100_cas.cpp2
-rw-r--r--src/lib/formats/fdd_dsk.cpp13
-rw-r--r--src/lib/formats/fdos_dsk.cpp9
-rw-r--r--src/lib/formats/flacfile.cpp78
-rw-r--r--src/lib/formats/flex_dsk.cpp9
-rw-r--r--src/lib/formats/flopimg.cpp66
-rw-r--r--src/lib/formats/flopimg.h69
-rw-r--r--src/lib/formats/flopimg_legacy.cpp9
-rw-r--r--src/lib/formats/fm7_cas.cpp2
-rw-r--r--src/lib/formats/fmsx_cas.cpp2
-rw-r--r--src/lib/formats/fs_cbmdos.cpp433
-rw-r--r--src/lib/formats/fs_coco_os9.cpp212
-rw-r--r--src/lib/formats/fs_coco_rsdos.cpp352
-rw-r--r--src/lib/formats/fs_fat.cpp686
-rw-r--r--src/lib/formats/fs_hp98x5.cpp116
-rw-r--r--src/lib/formats/fs_hplif.cpp72
-rw-r--r--src/lib/formats/fs_isis.cpp84
-rw-r--r--src/lib/formats/fs_oric_jasmin.cpp230
-rw-r--r--src/lib/formats/fs_prodos.cpp267
-rw-r--r--src/lib/formats/fs_unformatted.cpp40
-rw-r--r--src/lib/formats/fs_unformatted.h4
-rw-r--r--src/lib/formats/fs_vtech.cpp192
-rw-r--r--src/lib/formats/fsblk.cpp174
-rw-r--r--src/lib/formats/fsblk.h221
-rw-r--r--src/lib/formats/fsblk_vec.cpp14
-rw-r--r--src/lib/formats/fsblk_vec.h11
-rw-r--r--src/lib/formats/fsd_dsk.cpp14
-rw-r--r--src/lib/formats/fsmeta.cpp1
-rw-r--r--src/lib/formats/fsmeta.h1
-rw-r--r--src/lib/formats/g64_dsk.cpp28
-rw-r--r--src/lib/formats/gtp_cas.cpp2
-rw-r--r--src/lib/formats/h17disk.cpp253
-rw-r--r--src/lib/formats/h17disk.h38
-rw-r--r--src/lib/formats/h8_cas.cpp171
-rw-r--r--src/lib/formats/h8_cas.h4
-rw-r--r--src/lib/formats/hect_tap.cpp10
-rw-r--r--src/lib/formats/hp300_dsk.cpp2
-rw-r--r--src/lib/formats/hpi_dsk.cpp10
-rw-r--r--src/lib/formats/hti_tape.cpp137
-rw-r--r--src/lib/formats/hti_tape.h54
-rw-r--r--src/lib/formats/hxchfe_dsk.cpp29
-rw-r--r--src/lib/formats/hxcmfm_dsk.cpp24
-rw-r--r--src/lib/formats/ibmxdf_dsk.cpp8
-rw-r--r--src/lib/formats/idpart_dsk.cpp53
-rw-r--r--src/lib/formats/idpart_dsk.h32
-rw-r--r--src/lib/formats/imd_dsk.cpp11
-rw-r--r--src/lib/formats/img_dsk.cpp15
-rw-r--r--src/lib/formats/ipf_dsk.cpp96
-rw-r--r--src/lib/formats/ipf_dsk.h66
-rw-r--r--src/lib/formats/jfd_dsk.cpp14
-rw-r--r--src/lib/formats/juku_dsk.cpp10
-rw-r--r--src/lib/formats/juku_dsk.h4
-rw-r--r--src/lib/formats/jvc_dsk.cpp18
-rw-r--r--src/lib/formats/kc_cas.cpp12
-rw-r--r--src/lib/formats/kim1_cas.cpp2
-rw-r--r--src/lib/formats/lviv_lvt.cpp2
-rw-r--r--src/lib/formats/lw30_dsk.cpp11
-rw-r--r--src/lib/formats/m20_dsk.cpp13
-rw-r--r--src/lib/formats/mbee_cas.cpp2
-rw-r--r--src/lib/formats/mdos_dsk.cpp32
-rw-r--r--src/lib/formats/mfi_dsk.cpp50
-rw-r--r--src/lib/formats/mfi_dsk.h8
-rw-r--r--src/lib/formats/mz_cas.cpp2
-rw-r--r--src/lib/formats/nabupc_dsk.cpp7
-rw-r--r--src/lib/formats/nfd_dsk.cpp26
-rw-r--r--src/lib/formats/orao_cas.cpp2
-rw-r--r--src/lib/formats/oric_dsk.cpp31
-rw-r--r--src/lib/formats/oric_tap.cpp184
-rw-r--r--src/lib/formats/os9_dsk.cpp3
-rw-r--r--src/lib/formats/p6001_cas.cpp2
-rw-r--r--src/lib/formats/pasti_dsk.cpp12
-rw-r--r--src/lib/formats/pc98_dsk.cpp4
-rw-r--r--src/lib/formats/pc98fdi_dsk.cpp42
-rw-r--r--src/lib/formats/phc25_cas.cpp2
-rw-r--r--src/lib/formats/pmd_cas.cpp2
-rw-r--r--src/lib/formats/poly_dsk.cpp8
-rw-r--r--src/lib/formats/primoptp.cpp4
-rw-r--r--src/lib/formats/rk_cas.cpp8
-rw-r--r--src/lib/formats/rx50_dsk.cpp8
-rw-r--r--src/lib/formats/sap_dsk.cpp169
-rw-r--r--src/lib/formats/sap_dsk.h30
-rw-r--r--src/lib/formats/sdf_dsk.cpp12
-rw-r--r--src/lib/formats/sol_cas.cpp2
-rw-r--r--src/lib/formats/sorc_cas.cpp2
-rw-r--r--src/lib/formats/spc1000_cas.cpp4
-rw-r--r--src/lib/formats/st_dsk.cpp25
-rw-r--r--src/lib/formats/svi_cas.cpp2
-rw-r--r--src/lib/formats/svi_dsk.cpp9
-rw-r--r--src/lib/formats/td0_dsk.cpp20
-rw-r--r--src/lib/formats/thom_cas.cpp22
-rw-r--r--src/lib/formats/thom_dsk.cpp13
-rw-r--r--src/lib/formats/thom_dsk.h4
-rw-r--r--src/lib/formats/ti99_dsk.cpp23
-rw-r--r--src/lib/formats/trd_dsk.cpp9
-rw-r--r--src/lib/formats/trs80_dsk.cpp34
-rw-r--r--src/lib/formats/trs_cas.cpp2
-rw-r--r--src/lib/formats/tzx_cas.cpp117
-rw-r--r--src/lib/formats/uef_cas.cpp17
-rw-r--r--src/lib/formats/uniflex_dsk.cpp5
-rw-r--r--src/lib/formats/upd765_dsk.cpp10
-rw-r--r--src/lib/formats/vdk_dsk.cpp15
-rw-r--r--src/lib/formats/vg5k_cas.cpp2
-rw-r--r--src/lib/formats/vgi_dsk.cpp32
-rw-r--r--src/lib/formats/victor9k_dsk.cpp37
-rw-r--r--src/lib/formats/vt_cas.cpp6
-rw-r--r--src/lib/formats/vt_dsk.cpp73
-rw-r--r--src/lib/formats/vt_dsk.h2
-rw-r--r--src/lib/formats/wavfile.cpp1
-rw-r--r--src/lib/formats/wd177x_dsk.cpp6
-rw-r--r--src/lib/formats/x07_cas.cpp2
-rw-r--r--src/lib/formats/x1_tap.cpp2
-rw-r--r--src/lib/formats/zx81_p.cpp4
155 files changed, 5109 insertions, 2583 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(&sector_header[0]);
uint16_t compression = get_u16le(&sector_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 = &sect_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), &sector, sizeof(sector), actual);
+ read_at(io, track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), &sector, 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), &sector, sizeof(sector), actual);
+ read_at(io, track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j), &sector, 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 &sector_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(&sectdata[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 &sector_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, &sector, &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 &sector = *reinterpret_cast<const rsdos_dirent_sector *>(dir_block.rodata());
+ auto dir_block = read_sector(DIRECTORY_TRACK, dir_sector);
+ const rsdos_dirent_sector &sector = *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 &current_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 &current_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 &current_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 = &sector_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 = &sect_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 = &sector_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, &sector_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, &sector_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 &sect, 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 = &sector_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 = &sector_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;