diff options
Diffstat (limited to 'src/lib/formats/ap2_dsk.cpp')
-rw-r--r-- | src/lib/formats/ap2_dsk.cpp | 562 |
1 files changed, 345 insertions, 217 deletions
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); |