// license:BSD-3-Clause // copyright-holders:Nathan Woods /********************************************************************* iflopimg.c Bridge code for Imgtool into the standard floppy code *********************************************************************/ #include "imgtool.h" #include "formats/flopimg.h" #include "library.h" #include "iflopimg.h" imgtoolerr_t imgtool_floppy_error(floperr_t err) { switch(err) { case FLOPPY_ERROR_SUCCESS: return IMGTOOLERR_SUCCESS; case FLOPPY_ERROR_OUTOFMEMORY: return IMGTOOLERR_OUTOFMEMORY; case FLOPPY_ERROR_INVALIDIMAGE: return IMGTOOLERR_CORRUPTIMAGE; case FLOPPY_ERROR_SEEKERROR: return IMGTOOLERR_SEEKERROR; case FLOPPY_ERROR_UNSUPPORTED: return IMGTOOLERR_UNIMPLEMENTED; default: return IMGTOOLERR_UNEXPECTED; } } /********************************************************************* Imgtool ioprocs *********************************************************************/ static void imgtool_floppy_closeproc(void *file) { delete reinterpret_cast(file); } static int imgtool_floppy_seekproc(void *file, int64_t offset, int whence) { reinterpret_cast(file)->seek(offset, whence); return 0; } static size_t imgtool_floppy_readproc(void *file, void *buffer, size_t length) { return reinterpret_cast(file)->read(buffer, length); } static size_t imgtool_floppy_writeproc(void *file, const void *buffer, size_t length) { reinterpret_cast(file)->write(buffer, length); return length; } static uint64_t imgtool_floppy_filesizeproc(void *file) { return reinterpret_cast(file)->size(); } static const struct io_procs imgtool_ioprocs = { imgtool_floppy_closeproc, imgtool_floppy_seekproc, imgtool_floppy_readproc, imgtool_floppy_writeproc, imgtool_floppy_filesizeproc }; static const struct io_procs imgtool_noclose_ioprocs = { nullptr, imgtool_floppy_seekproc, imgtool_floppy_readproc, imgtool_floppy_writeproc, imgtool_floppy_filesizeproc }; /********************************************************************* Imgtool handlers *********************************************************************/ struct imgtool_floppy_image { floppy_image_legacy *floppy; }; static imgtoolerr_t imgtool_floppy_open_internal(imgtool::image &image, imgtool::stream::ptr &&stream, int noclose) { floperr_t ferr; imgtoolerr_t err = IMGTOOLERR_SUCCESS; imgtool::stream *f = nullptr; struct imgtool_floppy_image *fimg; const imgtool_class *imgclass; const struct FloppyFormat *format; imgtoolerr_t (*open)(imgtool::image &image, imgtool::stream *f); fimg = (struct imgtool_floppy_image *) image.extra_bytes(); imgclass = &image.module().imgclass; format = (const struct FloppyFormat *) imgclass->derived_param; open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); // extract the pointer f = stream.release(); // open up the floppy ferr = floppy_open(f, noclose ? &imgtool_noclose_ioprocs : &imgtool_ioprocs, "", format, FLOPPY_FLAGS_READWRITE, &fimg->floppy); if (ferr) { err = imgtool_floppy_error(ferr); goto done; } f = nullptr; // the floppy object has the stream now if (open) { err = open(image, nullptr); if (err) goto done; } done: if (f) delete f; if (err && fimg->floppy) { floppy_close(fimg->floppy); fimg->floppy = nullptr; } return err; } static imgtoolerr_t imgtool_floppy_open(imgtool::image &image, imgtool::stream::ptr &&stream) { return imgtool_floppy_open_internal(image, std::move(stream), false); } static imgtoolerr_t imgtool_floppy_create(imgtool::image &image, imgtool::stream::ptr &&stream, util::option_resolution *opts) { floperr_t ferr; imgtoolerr_t err = IMGTOOLERR_SUCCESS; imgtool::stream *f = nullptr; struct imgtool_floppy_image *fimg; const imgtool_class *imgclass; const struct FloppyFormat *format; imgtoolerr_t (*create)(imgtool::image &, imgtool::stream *, util::option_resolution *); imgtoolerr_t (*open)(imgtool::image &, imgtool::stream *f); fimg = (struct imgtool_floppy_image *) image.extra_bytes(); imgclass = &image.module().imgclass; format = (const struct FloppyFormat *) imgclass->derived_param; create = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *, util::option_resolution *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_CREATE); open = (imgtoolerr_t (*)(imgtool::image &, imgtool::stream *)) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_OPEN); // extract the pointer f = stream.release(); // open up the floppy ferr = floppy_create(f, &imgtool_ioprocs, format, opts, &fimg->floppy); if (ferr) { err = imgtool_floppy_error(ferr); goto done; } f = nullptr; // the floppy object has the stream now // do we have to do extra stuff when creating the image? if (create) { err = create(image, nullptr, opts); if (err) goto done; } // do we have to do extra stuff when opening the image? if (open) { err = open(image, nullptr); if (err) goto done; } done: if (f) delete f; if (err && fimg->floppy) { floppy_close(fimg->floppy); fimg->floppy = nullptr; } return err; } static void imgtool_floppy_close(imgtool::image &img) { floppy_close(imgtool_floppy(img)); } static imgtoolerr_t imgtool_floppy_read_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, std::vector &buffer) { floperr_t ferr; uint32_t sector_size; // get the sector length ferr = floppy_get_sector_length(imgtool_floppy(image), head, track, sector, §or_size); if (ferr) return imgtool_floppy_error(ferr); // resize the buffer accordingly try { buffer.resize(sector_size); } catch (std::bad_alloc const &) { return IMGTOOLERR_OUTOFMEMORY; } // and read the sector ferr = floppy_read_sector(imgtool_floppy(image), head, track, sector, 0, &buffer[0], sector_size); if (ferr) return imgtool_floppy_error(ferr); return IMGTOOLERR_SUCCESS; } static imgtoolerr_t imgtool_floppy_write_sector(imgtool::image &image, uint32_t track, uint32_t head, uint32_t sector, const void *buffer, size_t len, int ddam) { floperr_t ferr; ferr = floppy_write_sector(imgtool_floppy(image), head, track, sector, 0, buffer, len, ddam); if (ferr) return imgtool_floppy_error(ferr); return IMGTOOLERR_SUCCESS; } static void imgtool_floppy_get_info(const imgtool_class *imgclass, uint32_t state, union imgtoolinfo *info) { const struct FloppyFormat *format; imgtool_class derived_class; format = (const struct FloppyFormat *) imgclass->derived_param; memset(&derived_class, 0, sizeof(derived_class)); derived_class.get_info = imgclass->derived_get_info; switch(state) { /* --- the following bits of info are returned as 64-bit signed integers --- */ case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(struct imgtool_floppy_image) + imgtool_get_info_int(&derived_class, IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES); break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case IMGTOOLINFO_STR_NAME: sprintf(info->s = imgtool_temp_str(), "%s_%s", format->name, imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_NAME)); break; case IMGTOOLINFO_STR_DESCRIPTION: sprintf(info->s = imgtool_temp_str(), "%s (%s)", format->description, imgtool_get_info_string(&derived_class, IMGTOOLINFO_STR_DESCRIPTION)); break; case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), format->extensions); break; case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: info->p = (void*)format->param_guidelines; break; /* --- the following bits of info are returned as pointers to data or functions --- */ case IMGTOOLINFO_PTR_OPEN: info->open = imgtool_floppy_open; break; case IMGTOOLINFO_PTR_CREATE: info->create = imgtool_floppy_create; break; case IMGTOOLINFO_PTR_CLOSE: info->close = imgtool_floppy_close; break; case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = format->param_guidelines ? &floppy_option_guide : nullptr; break; case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = imgtool_floppy_read_sector; break; case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = imgtool_floppy_write_sector; break; default: imgclass->derived_get_info(imgclass, state, info); break; } } int imgtool_floppy_make_class(int index, imgtool_class *imgclass) { const struct FloppyFormat *format; /* get the format */ format = (const struct FloppyFormat *) imgtool_get_info_ptr(imgclass, IMGTOOLINFO_PTR_FLOPPY_FORMAT); assert(format); if (!format[index].construct) return false; imgclass->derived_get_info = imgclass->get_info; imgclass->get_info = imgtool_floppy_get_info; imgclass->derived_param = (void *) &format[index]; return true; } floppy_image_legacy *imgtool_floppy(imgtool::image &img) { struct imgtool_floppy_image *fimg; fimg = (struct imgtool_floppy_image *) img.extra_bytes(); return fimg->floppy; } static imgtoolerr_t imgtool_floppy_transfer_sector_tofrom_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f, int direction) { floperr_t err; floppy_image_legacy *floppy; std::vector buffer; floppy = imgtool_floppy(img); buffer.resize(length); if (direction) { err = floppy_read_sector(floppy, head, track, sector, offset, &buffer[0], length); if (err) goto done; f.write(&buffer[0], length); } else { f.read(&buffer[0], length); err = floppy_write_sector(floppy, head, track, sector, offset, &buffer[0], length, 0); /* TODO: pass ddam argument from imgtool */ if (err) goto done; } err = FLOPPY_ERROR_SUCCESS; done: return imgtool_floppy_error(err); } imgtoolerr_t imgtool_floppy_read_sector_to_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f) { return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 1); } imgtoolerr_t imgtool_floppy_write_sector_from_stream(imgtool::image &img, int head, int track, int sector, int offset, size_t length, imgtool::stream &f) { return imgtool_floppy_transfer_sector_tofrom_stream(img, head, track, sector, offset, length, f, 0); } void *imgtool_floppy_extrabytes(imgtool::image &img) { struct imgtool_floppy_image *fimg; fimg = (struct imgtool_floppy_image *) img.extra_bytes(); return fimg + 1; }