From d43d8bcecf4a5515012f73165f72813ee21cd8e3 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 24 Apr 2018 18:24:33 +0200 Subject: apple2: Add WOZ format [O. Galibert] --- src/lib/formats/ap2_dsk.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++- src/lib/formats/ap2_dsk.h | 25 +++++++++ src/lib/formats/flopimg.cpp | 17 ++++-- src/lib/formats/flopimg.h | 4 +- 4 files changed, 163 insertions(+), 6 deletions(-) (limited to 'src/lib') diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp index 0105fbfa679..8e9f37977e9 100644 --- a/src/lib/formats/ap2_dsk.cpp +++ b/src/lib/formats/ap2_dsk.cpp @@ -1547,7 +1547,7 @@ const char *a2_edd_format::extensions() const bool a2_edd_format::supports_save() const { - return true; + return false; } int a2_edd_format::identify(io_generic *io, uint32_t form_factor) @@ -1645,3 +1645,124 @@ bool a2_edd_format::load(io_generic *io, uint32_t form_factor, floppy_image *ima } const floppy_format_type FLOPPY_EDD_FORMAT = &floppy_image_format_creator; + + +a2_woz_format::a2_woz_format() : floppy_image_format_t() +{ +} + +const char *a2_woz_format::name() const +{ + return "a2_woz"; +} + +const char *a2_woz_format::description() const +{ + return "Apple II WOZ Image"; +} + +const char *a2_woz_format::extensions() const +{ + return "woz"; +} + +bool a2_woz_format::supports_save() const +{ + return false; +} + +const uint8_t a2_woz_format::signature[8] = { 0x57, 0x4f, 0x5a, 0x31, 0xff, 0x0a, 0x0d, 0x0a }; + +int a2_woz_format::identify(io_generic *io, uint32_t form_factor) +{ + uint8_t header[8]; + io_generic_read(io, header, 0, 8); + return !memcmp(header, signature, 8) ? 100 : 0; +} + +bool a2_woz_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) +{ + std::vector img(io_generic_size(io)); + io_generic_read(io, &img[0], 0, img.size()); + + // 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)) + 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); + + if(!off_info || !off_tmap || !off_trks) + return false; + if(r8(img, off_info + 0) != 1) + return false; + + bool is_35 = r8(img, off_info + 1) == 2; + if((form_factor == floppy_image::FF_35 && !is_35) || (form_factor == floppy_image::FF_525 && is_35)) + return false; + + unsigned int limit = is_35 ? 160 : 141; + 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); + if(idx != 0xff) { + uint32_t boff = off_trks + 6656*idx; + generate_track_from_bitstream(track, head, &img[boff], r16(img, boff + 6648), image, subtrack, r16(img, boff + 6650)); + } + } + + return true; +} + +uint32_t a2_woz_format::find_tag(const std::vector &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; +} + +uint32_t a2_woz_format::r32(const std::vector &data, uint32_t offset) +{ + return data[offset] | (data[offset+1] << 8) | (data[offset+2] << 16) | (data[offset+3] << 24); +} + +uint16_t a2_woz_format::r16(const std::vector &data, uint32_t offset) +{ + return data[offset] | (data[offset+1] << 8); +} + +uint8_t a2_woz_format::r8(const std::vector &data, uint32_t offset) +{ + return data[offset]; +} + +uint32_t a2_woz_format::crc32r(const uint8_t *data, uint32_t size) +{ + // Reversed crc32 + uint32_t crc = 0xffffffff; + for(uint32_t i=0; i != size; i++) { + crc = crc ^ data[i]; + for(int j=0; j<8; j++) + if(crc & 1) + crc = (crc >> 1) ^ 0xedb88320; + else + crc = crc >> 1; + } + return ~crc; +} + + +const floppy_format_type FLOPPY_WOZ_FORMAT = &floppy_image_format_creator; diff --git a/src/lib/formats/ap2_dsk.h b/src/lib/formats/ap2_dsk.h index 3d140ac86e9..3dcf423ee83 100644 --- a/src/lib/formats/ap2_dsk.h +++ b/src/lib/formats/ap2_dsk.h @@ -102,4 +102,29 @@ private: extern const floppy_format_type FLOPPY_EDD_FORMAT; +class a2_woz_format : public floppy_image_format_t +{ +public: + a2_woz_format(); + + 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 supports_save() const override; + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + +private: + static const uint8_t signature[8]; + + static uint32_t r32(const std::vector &data, uint32_t offset); + static uint16_t r16(const std::vector &data, uint32_t offset); + static uint8_t r8(const std::vector &data, uint32_t offset); + static uint32_t crc32r(const uint8_t *data, uint32_t size); + static uint32_t find_tag(const std::vector &data, uint32_t tag); +}; + +extern const floppy_format_type FLOPPY_WOZ_FORMAT; + #endif /* AP2_DISK_H */ diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index d517c240a80..4ffe3e720ad 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -1679,16 +1679,24 @@ void floppy_image_format_t::normalize_times(std::vector &buffer) } } -void floppy_image_format_t::generate_track_from_bitstream(int track, int head, const uint8_t *trackbuf, int track_size, floppy_image *image, int subtrack) +void floppy_image_format_t::generate_track_from_bitstream(int track, int head, const uint8_t *trackbuf, int track_size, floppy_image *image, int subtrack, int splice) { - // Maximal number of cells which happens when the buffer is all 1 + if(splice >= track_size) + splice = 0; + std::vector &dest = image->get_buffer(track, head, subtrack); dest.clear(); + int inversions = 0; + for(int i=0; i != track_size; i++) + if(trackbuf[i >> 3] & (0x80 >> (i & 7))) + inversions++; + int invert_splice = inversions & 1 ? splice : -1; + uint32_t cbit = floppy_image::MG_A; uint32_t count = 0; for(int i=0; i != track_size; i++) - if(trackbuf[i >> 3] & (0x80 >> (i & 7))) { + if((i == invert_splice) ^ !!(trackbuf[i >> 3] & (0x80 >> (i & 7)))) { dest.push_back(cbit | (count+1)); cbit = cbit == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; count = 1; @@ -1699,7 +1707,8 @@ void floppy_image_format_t::generate_track_from_bitstream(int track, int head, c dest.push_back(cbit | count); normalize_times(dest); - image->set_write_splice_position(track, head, 0, subtrack); + int splpos = uint64_t(200000000) * splice / track_size; + image->set_write_splice_position(track, head, splpos, subtrack); } void floppy_image_format_t::generate_track_from_levels(int track, int head, std::vector &trackbuf, int splice_pos, floppy_image *image) diff --git a/src/lib/formats/flopimg.h b/src/lib/formats/flopimg.h index 781a3687209..7617daabdc4 100644 --- a/src/lib/formats/flopimg.h +++ b/src/lib/formats/flopimg.h @@ -386,8 +386,10 @@ protected: @param trackbuf track input buffer. @param track_size in cells, not bytes. @param image + @param subtrack subtrack index, 0-3 + @param splice write splice position */ - void generate_track_from_bitstream(int track, int head, const uint8_t *trackbuf, int track_size, floppy_image *image, int subtrack = 0); + void generate_track_from_bitstream(int track, int head, const uint8_t *trackbuf, int track_size, floppy_image *image, int subtrack = 0, int splice = 0); //! @brief Generate a track from cell level values (0/1/W/D/N). -- cgit v1.2.3