From 16be7cb5b7f8aac7d30c9d1de84b5c9bbec391cf Mon Sep 17 00:00:00 2001 From: lfantoniosi Date: Sat, 13 Jun 2020 20:16:36 -0700 Subject: Add ImageDisk IMD save support Allow to save IMD floppy image disk. Tested on Zorba and Kaypro II --- src/lib/formats/imd_dsk.cpp | 182 +++++++++++++++++++++++++++++++++++--------- src/lib/formats/imd_dsk.h | 13 +++- 2 files changed, 158 insertions(+), 37 deletions(-) diff --git a/src/lib/formats/imd_dsk.cpp b/src/lib/formats/imd_dsk.cpp index b31e7dfb11f..030b99e14b7 100644 --- a/src/lib/formats/imd_dsk.cpp +++ b/src/lib/formats/imd_dsk.cpp @@ -430,6 +430,9 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) for(pos=0; pos < size && img[pos] != 0x1a; pos++) {}; pos++; + m_comment.resize(pos); + memcpy(&m_comment[0], &img[0], pos); + if(pos >= size) return false; @@ -437,64 +440,83 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) image->get_maximal_geometry(tracks, heads); while(pos < size) { - uint8_t mode = img[pos++]; - uint8_t track = img[pos++]; - uint8_t head = img[pos++]; - uint8_t sector_count = img[pos++]; - uint8_t ssize = img[pos++]; + m_mode.push_back(img[pos++]); + m_track.push_back(img[pos++]); + m_head.push_back(img[pos++]); + m_sector_count.push_back(img[pos++]); + m_ssize.push_back(img[pos++]); - if(track >= tracks) + if(m_track.back() >= tracks) { - osd_printf_error("imd_format: Track %d exceeds maximum of %d\n", track, tracks); + osd_printf_error("imd_format: Track %d exceeds maximum of %d\n", m_track.back(), tracks); return false; } - if((head & 0x3f) >= heads) + if((m_head.back() & 0x3f) >= heads) { - osd_printf_error("imd_format: Head %d exceeds maximum of %d\n", head & 0x3f, heads); + osd_printf_error("imd_format: Head %d exceeds maximum of %d\n", m_head.back() & 0x3f, heads); return false; } - if(ssize == 0xff) + if(m_ssize.back() == 0xff) { - osd_printf_error("imd_format: Unsupported variable sector size on track %d head %d", track, head & 0x3f); + osd_printf_error("imd_format: Unsupported variable sector size on track %d head %d", m_track.back(), m_head.back() & 0x3f); return false; } - uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192; + uint32_t actual_size = m_ssize.back() < 7 ? 128 << m_ssize.back() : 8192; static const int rates[3] = { 500000, 300000, 250000 }; - bool fm = mode < 3; - int rate = rates[mode % 3]; + bool fm = m_mode.back() < 3; + int rate = rates[m_mode.back() % 3]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int cell_count = (fm ? 1 : 2)*rate*60/rpm; - const uint8_t *snum = &img[pos]; - pos += sector_count; - const uint8_t *tnum = head & 0x80 ? &img[pos] : nullptr; - if(tnum) - pos += sector_count; - const uint8_t *hnum = head & 0x40 ? &img[pos] : nullptr; - if(hnum) - pos += sector_count; + //const uint8_t *snum = &img[pos]; + m_snum.push_back(std::vector(m_sector_count.back())); + memcpy(&m_snum.back()[0], &img[pos], m_sector_count.back()); + pos += m_sector_count.back(); + + //const uint8_t *tnum = head & 0x80 ? &img[pos] : nullptr; + if (m_head.back() & 0x80) + { + m_tnum.push_back(std::vector(m_sector_count.back())); + memcpy(&m_tnum.back()[0], &img[pos], m_sector_count.back()); + pos += m_sector_count.back(); + } + else + { + m_tnum.push_back(std::vector(0)); + } + + //const uint8_t *hnum = head & 0x40 ? &img[pos] : nullptr; + if (m_head.back() & 0x40) + { + m_hnum.push_back(std::vector(m_sector_count.back())); + memcpy(&m_hnum.back()[0], &img[pos], m_sector_count.back()); + pos += m_sector_count.back(); + } + else + { + m_hnum.push_back(std::vector(0)); + } - head &= 0x3f; + uint8_t head = m_head.back() & 0x3f; int gap_3 = calc_default_pc_gap3_size(form_factor, actual_size); desc_pc_sector sects[256]; - for(int i=0; i 8) { sects[i].data = nullptr; - } else { sects[i].deleted = stype == 3 || stype == 4 || stype == 7 || stype == 8; sects[i].bad_crc = stype == 5 || stype == 6 || stype == 7 || stype == 8; @@ -502,7 +524,6 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) if(stype == 2 || stype == 4 || stype == 6 || stype == 8) { sects[i].data = global_alloc_array(uint8_t, actual_size); memset(sects[i].data, img[pos++], actual_size); - } else { sects[i].data = &img[pos]; pos += actual_size; @@ -510,15 +531,15 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) } } - if(sector_count) { + if(m_sector_count.back()) { if(fm) { - build_pc_track_fm(track, head, image, cell_count, sector_count, sects, gap_3); + build_pc_track_fm(m_track.back(), head, image, cell_count, m_sector_count.back(), sects, gap_3); } else { - build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, gap_3); + build_pc_track_mfm(m_track.back(), head, image, cell_count, m_sector_count.back(), sects, gap_3); } } - for(int i=0; i= (&img[0] + size))) global_free_array(sects[i].data); } @@ -526,10 +547,99 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) return true; } +bool can_compress(const uint8_t* buffer, uint8_t ptrn, uint64_t size) +{ + for (; size > 0; size--) + if (*buffer++ != ptrn) + return false; + return true; +} + +bool imd_format::save(io_generic* io, floppy_image* image) +{ + uint64_t pos = 0; + io_generic_write(io, &m_comment[0], pos, m_comment.size()); + pos += m_comment.size(); + + for (int i = 0; i < m_mode.size(); i++) + { + io_generic_write(io, &m_mode[i], pos++, 1); + io_generic_write(io, &m_track[i], pos++, 1); + io_generic_write(io, &m_head[i], pos++, 1); + io_generic_write(io, &m_sector_count[i], pos++, 1); + io_generic_write(io, &m_ssize[i], pos++, 1); + + io_generic_write(io, &m_snum[i][0], pos, m_sector_count[i]); + pos += m_sector_count[i]; + + if (m_tnum[i].size()) + { + io_generic_write(io, &m_tnum[i][0], pos, m_sector_count[i]); + pos += m_sector_count[i]; + } + + if (m_hnum[i].size()) + { + io_generic_write(io, &m_hnum[i][0], pos, m_sector_count[i]); + pos += m_sector_count[i]; + } + + uint32_t actual_size = m_ssize[i] < 7 ? 128 << m_ssize[i] : 8192; + uint8_t head = m_head[i] & 0x3f; + + bool fm = m_mode[i]< 3; + + uint8_t bitstream[500000 / 8]; + uint8_t sector_data[50000]; + desc_xs sectors[256]; + int track_size; + generate_bitstream_from_track(m_track[i], head, 2000, bitstream, track_size, image); + if (fm) + extract_sectors_from_bitstream_fm_pc(bitstream, track_size, sectors, sector_data, sizeof(sector_data)); + else + extract_sectors_from_bitstream_mfm_pc(bitstream, track_size, sectors, sector_data, sizeof(sector_data)); + + uint8_t sdata[8192]; + for (int j = 0; j < m_sector_count[i]; j++) { + + desc_xs& xs = sectors[m_snum[i][j]]; + + uint8_t mode; + if (!xs.data) + { + mode = 0; + io_generic_write(io, &mode, pos++, 1); + continue; + } + else if (xs.size < actual_size) { + memcpy((void*)sdata, xs.data, xs.size); + memset((uint8_t*)sdata + xs.size, 0, xs.size - actual_size); + } + else + memcpy((void*)sdata, xs.data, actual_size); + + if (can_compress(sdata, sdata[0], actual_size)) + { + mode = 2; + io_generic_write(io, &mode, pos++, 1); + io_generic_write(io, &sdata[0], pos++, 1); + } + else + { + mode = 1; + io_generic_write(io, &mode, pos++, 1); + io_generic_write(io, &sdata, pos, actual_size); + pos += actual_size; + } + } + } + + return true; +} bool imd_format::supports_save() const { - return false; + return true; } const floppy_format_type FLOPPY_IMD_FORMAT = &floppy_image_format_creator; diff --git a/src/lib/formats/imd_dsk.h b/src/lib/formats/imd_dsk.h index 39e43329969..dd413ae9568 100644 --- a/src/lib/formats/imd_dsk.h +++ b/src/lib/formats/imd_dsk.h @@ -12,7 +12,6 @@ #include "flopimg.h" - class imd_format : public floppy_image_format_t { public: @@ -20,6 +19,7 @@ public: virtual int identify(io_generic *io, uint32_t form_factor) override; virtual bool load(io_generic *io, uint32_t form_factor, floppy_image *image) override; + virtual bool save(io_generic* io, floppy_image* image) override; virtual const char *name() const override; virtual const char *description() const override; @@ -28,6 +28,17 @@ public: private: void fixnum(char *start, char *end) const; + + std::vector m_comment; + std::vector > m_snum; + std::vector > m_tnum; + std::vector > m_hnum; + + std::vector m_mode; + std::vector m_track; + std::vector m_head; + std::vector m_sector_count; + std::vector m_ssize; }; extern const floppy_format_type FLOPPY_IMD_FORMAT; -- cgit v1.2.3