diff options
Diffstat (limited to 'src/lib/formats/td0_dsk.cpp')
-rw-r--r-- | src/lib/formats/td0_dsk.cpp | 210 |
1 files changed, 115 insertions, 95 deletions
diff --git a/src/lib/formats/td0_dsk.cpp b/src/lib/formats/td0_dsk.cpp index b7c418af53c..956bbd002c7 100644 --- a/src/lib/formats/td0_dsk.cpp +++ b/src/lib/formats/td0_dsk.cpp @@ -2,7 +2,7 @@ // copyright-holders:Miodrag Milanovic /********************************************************************* - formats/td0_dsk.c + formats/td0_dsk.cpp TD0 disk images @@ -14,10 +14,14 @@ * Edited and translated to English by Kenji RIKITAKE */ -#include <string.h> -#include <assert.h> -#include "pool.h" -#include "flopimg.h" +#include "flopimg_legacy.h" + +#include "ioprocs.h" +#include "multibyte.h" + +#include <cstring> +#include <tuple> + #define BUFSZ 512 // new input buffer @@ -49,17 +53,26 @@ struct td0dsk_tag }; struct tdlzhuf { - uint16_t r, - bufcnt,bufndx,bufpos, // string buffer + uint16_t r = 0, + bufcnt = 0, bufndx = 0, bufpos = 0, // string buffer // the following to allow block reads from input in next_word() - ibufcnt,ibufndx; // input buffer counters - uint8_t inbuf[BUFSZ]; // input buffer + ibufcnt = 0, ibufndx = 0; // input buffer counters + uint8_t inbuf[BUFSZ]{}; // input buffer }; struct td0dsk_t { - io_generic *floppy_file; +public: + td0dsk_t(util::random_read &f) : floppy_file(f) { } + + void set_floppy_file_offset(uint64_t o) { floppy_file_offset = o; } + + void init_Decode(); + int Decode(uint8_t *buf, int len); + +private: + util::random_read &floppy_file; uint64_t floppy_file_offset; struct tdlzhuf tdctl; @@ -79,7 +92,7 @@ struct td0dsk_t uint8_t getlen; int data_read(uint8_t *buf, uint16_t size); - int next_word(); + int next_word(int needed); int GetBit(); int GetByte(); void StartHuff(); @@ -87,33 +100,10 @@ struct td0dsk_t void update(int c); int16_t DecodeChar(); int16_t DecodePosition(); - void init_Decode(); - int Decode(uint8_t *buf, int len); }; //static td0dsk_t td0dsk; -struct floppy_image_legacy -{ - struct io_generic io; - - const struct FloppyFormat *floppy_option; - struct FloppyCallbacks format; - - /* loaded track stuff */ - int loaded_track_head; - int loaded_track_index; - uint32_t loaded_track_size; - void *loaded_track_data; - uint8_t loaded_track_status; - uint8_t flags; - - /* tagging system */ - object_pool *tags; - void *tag_data; -}; - - static struct td0dsk_tag *get_tag(floppy_image_legacy *floppy) { struct td0dsk_tag *tag; @@ -186,7 +176,7 @@ static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, in offs+= 6; if ((header[4] & 0x30)==0) { offs+= 2; - offs+= header[6] + (header[7]<<8); + offs+= get_u16le(&header[6]); } } // read size of sector @@ -225,7 +215,7 @@ static floperr_t internal_td0_read_sector(floppy_image_legacy *floppy, int head, offset+=3; // take data size - size = header[6] + (header[7]<<8)-1; + size = get_u16le(&header[6])-1; // take real sector size realsize = 1 << (header[3] + 7); @@ -246,7 +236,7 @@ static floperr_t internal_td0_read_sector(floppy_image_legacy *floppy, int head, // - 2 bytes of data // data is reapeted specified number of times while(buff_pos<realsize) { - for (i=0;i<data[data_pos]+(data[data_pos+1] << 8);i++) { + for (i=0;i<get_u16le(&data[data_pos]);i++) { buf[buff_pos] = data[data_pos+2];buff_pos++; buf[buff_pos] = data[data_pos+3];buff_pos++; } @@ -336,11 +326,12 @@ static floperr_t td0_get_indexed_sector_info(floppy_image_legacy *floppy, int he int td0dsk_t::data_read(uint8_t *buf, uint16_t size) { - uint64_t image_size = io_generic_size(floppy_file); + uint64_t image_size = 0; + floppy_file.length(image_size); if (size > image_size - floppy_file_offset) { size = image_size - floppy_file_offset; } - io_generic_read(floppy_file,buf,floppy_file_offset,size); + /*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; } @@ -422,16 +413,15 @@ static const uint8_t d_len[256] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }; -int td0dsk_t::next_word() +int td0dsk_t::next_word(int needed) { - if(tdctl.ibufndx >= tdctl.ibufcnt) - { - tdctl.ibufndx = 0; - tdctl.ibufcnt = data_read(tdctl.inbuf,BUFSZ); - if(tdctl.ibufcnt <= 0) - return(-1); - } while (getlen <= 8) { // typically reads a word at a time + if(tdctl.ibufndx >= tdctl.ibufcnt) { + tdctl.ibufndx = 0; + tdctl.ibufcnt = data_read(tdctl.inbuf,BUFSZ); + if(tdctl.ibufcnt <= 0) + return(getlen >= needed ? 0 : -1); + } getbuf |= tdctl.inbuf[tdctl.ibufndx++] << (8 - getlen); getlen += 8; } @@ -442,7 +432,7 @@ int td0dsk_t::next_word() int td0dsk_t::GetBit() /* get one bit */ { int16_t i; - if(next_word() < 0) + if(next_word(1) < 0) return(-1); i = getbuf; getbuf <<= 1; @@ -456,7 +446,7 @@ int td0dsk_t::GetBit() /* get one bit */ int td0dsk_t::GetByte() /* get a byte */ { uint16_t i; - if(next_word() != 0) + if(next_word(8) != 0) return(-1); i = getbuf; getbuf <<= 8; @@ -653,7 +643,7 @@ int td0dsk_t::Decode(uint8_t *buf, int len) /* Decoding/Uncompressing */ } else { if((pos = DecodePosition()) < 0) - return(count); // fatal error + return(count); // fatal error tdctl.bufpos = (tdctl.r - pos - 1) & (N - 1); tdctl.bufcnt = c - 255 + THRESHOLD; tdctl.bufndx = 0; @@ -679,7 +669,6 @@ int td0dsk_t::Decode(uint8_t *buf, int len) /* Decoding/Uncompressing */ FLOPPY_CONSTRUCT( td0_dsk_construct ) { - td0dsk_t state; struct FloppyCallbacks *callbacks; struct td0dsk_tag *tag; uint8_t *header; @@ -710,9 +699,9 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) int rd; int off = 12; int size = 0; - state.floppy_file = &(floppy->io); + td0dsk_t state(floppy_get_io(floppy)); state.init_Decode(); - state.floppy_file_offset = 12; + state.set_floppy_file_offset(12); do { if((rd = state.Decode(obuf, BUFSZ)) > 0) size += rd; @@ -724,7 +713,7 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) return FLOPPY_ERROR_OUTOFMEMORY; } memcpy(tag->data,obuf,12); - state.floppy_file_offset = 12; + state.set_floppy_file_offset(12); state.init_Decode(); do { @@ -743,7 +732,7 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) // header len + comment header + comment len position = 12; if (header[7] & 0x80) { - position += 10 + header[14] + (header[15]<<8); + position += 10 + get_u16le(&header[14]); } tag->tracks = 0; do { @@ -764,7 +753,7 @@ FLOPPY_CONSTRUCT( td0_dsk_construct ) header = tag->data + position; position+=2; // skip sector data - position+= header[0] + (header[1]<<8); + position+= get_u16le(&header[0]); } } tag->tracks++; @@ -792,7 +781,7 @@ FLOPPY_DESTRUCT( td0_dsk_destruct ) /********************************************************************* - formats/td0_dsk.h + formats/td0_dsk.cpp Teledisk disk images @@ -804,60 +793,75 @@ td0_format::td0_format() { } -const char *td0_format::name() const +const char *td0_format::name() const noexcept { return "td0"; } -const char *td0_format::description() const +const char *td0_format::description() const noexcept { return "Teledisk disk image"; } -const char *td0_format::extensions() const +const char *td0_format::extensions() const noexcept { return "td0"; } -int td0_format::identify(io_generic *io, uint32_t form_factor) +int td0_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const { 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_generic_read(io, h, 0, 7); if(((h[0] == 'T') && (h[1] == 'D')) || ((h[0] == 't') && (h[1] == 'd'))) { - return 100; + return FIFID_SIGN; } return 0; } -bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +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; int track_spt; 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]; - io_generic_read(io, header, 0, 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]; if(header[0] == 't') { - td0dsk_t disk_decode; + td0dsk_t disk_decode(io); - disk_decode.floppy_file = io; disk_decode.init_Decode(); - disk_decode.floppy_file_offset = 12; - disk_decode.Decode(&imagebuf[0], max_size); + disk_decode.set_floppy_file_offset(12); + actual = disk_decode.Decode(&imagebuf[0], max_size); } else - io_generic_read(io, &imagebuf[0], 12, io_generic_size(io)); + { + uint64_t image_size; + if(io.length(image_size)) + return false; + std::tie(err, actual) = read_at(io, 12, &imagebuf[0], image_size - 12); + if(err || (actual != (image_size - 12))) + return false; + } + // skip optional comment section if(header[7] & 0x80) - offset = 10 + imagebuf[2] + (imagebuf[3] << 8); + offset = 10 + get_u16le(&imagebuf[2]); track_spt = imagebuf[offset]; if(track_spt == 255) // Empty file? @@ -869,44 +873,45 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) - image->set_variant(floppy_image::DSHD); + image.set_variant(floppy_image::DSHD); else return false; // single side hd? break; } - /* no break; could be qd, won't know until tracks are counted */ + // could be qd, won't know until tracks are counted + [[fallthrough]]; case 1: if(head_count == 2) - image->set_variant(floppy_image::DSDD); + image.set_variant(floppy_image::DSDD); else - image->set_variant(floppy_image::SSDD); + image.set_variant(floppy_image::SSDD); break; case 4: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) - image->set_variant(floppy_image::DSHD); + image.set_variant(floppy_image::DSHD); else return false; // single side 3.5? break; } else - image->set_variant(floppy_image::SSDD); - break; + image.set_variant(floppy_image::SSDD); + break; // FIXME: comment below says "no break" but this is a breal /* no break */ case 3: if(head_count == 2) { if(form_factor == floppy_image::FF_525) - image->set_variant(floppy_image::DSQD); + image.set_variant(floppy_image::DSQD); else - image->set_variant(floppy_image::DSDD); + image.set_variant(floppy_image::DSDD); } else { if(form_factor == floppy_image::FF_525) - image->set_variant(floppy_image::SSQD); + image.set_variant(floppy_image::SSQD); else - return false; // single side 3.5? + image.set_variant(floppy_image::SSDD); } break; case 5: @@ -922,6 +927,9 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) while(track_spt != 255) { + if(actual < offset + 4) + return false; + desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; @@ -931,6 +939,9 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) offset += 4; for(int i = 0; i < track_spt; i++) { + if(actual < offset + 6) + return false; + uint8_t *hs = &imagebuf[offset]; uint16_t size; offset += 6; @@ -947,6 +958,8 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) else { offset += 3; + if(actual < offset) + return false; size = 128 << hs[3]; int j, k; switch(hs[8]) @@ -954,12 +967,16 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) default: return false; case 0: + if(actual < offset + size) + return false; memcpy(§_data[sdatapos], &imagebuf[offset], size); offset += size; break; case 1: offset += 4; - k = (hs[9] + (hs[10] << 8)) * 2; + if(actual < offset) + return false; + k = get_u16le(&hs[9]) * 2; k = (k <= size) ? k : size; for(j = 0; j < k; j += 2) { @@ -973,11 +990,15 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) k = 0; while(k < size) { + if(actual < offset + 2) + return false; uint16_t len = imagebuf[offset]; uint16_t rep = imagebuf[offset + 1]; offset += 2; if(!len) { + if(actual < offset + rep) + return false; memcpy(§_data[sdatapos + k], &imagebuf[offset], rep); offset += rep; k += rep; @@ -985,6 +1006,8 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) else { len = (1 << len); + if(actual < offset + len) + return false; rep = len * rep; rep = ((rep + k) <= size) ? rep : (size - k); for(j = 0; j < rep; j += len) @@ -1014,27 +1037,24 @@ bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) else build_pc_track_mfm(track, head, image, base_cell_count*2, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); + if(actual <= offset) + return false; track_spt = imagebuf[offset]; } if((track_count > 50) && (form_factor == floppy_image::FF_525)) // ? { - if(image->get_variant() == floppy_image::DSDD) - image->set_variant(floppy_image::DSQD); - else if(image->get_variant() == floppy_image::SSDD) - image->set_variant(floppy_image::SSQD); + if(image.get_variant() == floppy_image::DSDD) + image.set_variant(floppy_image::DSQD); + else if(image.get_variant() == floppy_image::SSDD) + image.set_variant(floppy_image::SSQD); } return true; } -bool td0_format::save(io_generic *io, floppy_image *image) -{ - return false; -} - -bool td0_format::supports_save() const +bool td0_format::supports_save() const noexcept { return false; } -const floppy_format_type FLOPPY_TD0_FORMAT = &floppy_image_format_creator<td0_format>; +const td0_format FLOPPY_TD0_FORMAT; |