bool apd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint64_t size = io_generic_size(io); std::vector<uint8_t> img(size); io_generic_read(io, &img[0], 0, size); int err; std::vector<uint8_t> gz_ptr; z_stream d_stream; int inflate_size = (img[size - 1] << 24) | (img[size - 2] << 16) | (img[size - 3] << 8) | img[size - 4]; uint8_t *in_ptr = &img[0]; if (!memcmp(&img[0], GZ_HEADER, sizeof(GZ_HEADER))) { gz_ptr.resize(inflate_size); d_stream.zalloc = nullptr; d_stream.zfree = nullptr; d_stream.opaque = nullptr; d_stream.next_in = in_ptr; d_stream.avail_in = size; d_stream.next_out = &gz_ptr[0]; d_stream.avail_out = inflate_size; err = inflateInit2(&d_stream, MAX_WBITS | 16); if (err != Z_OK) { LOG_FORMATS("inflateInit2 error: %d\n", err); return false; } err = inflate(&d_stream, Z_FINISH); if (err != Z_STREAM_END && err != Z_OK) { LOG_FORMATS("inflate error: %d\n", err); return false; } err = inflateEnd(&d_stream); if (err != Z_OK) { LOG_FORMATS("inflateEnd error: %d\n", err); return false; } size = inflate_size; img = gz_ptr; } int data = 0x7d0; for (int track = 0; track < 166; track++) { uint32_t sdlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x0])); uint32_t ddlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x4])); uint32_t qdlen = little_endianize_int32(*(uint32_t *)(&img[(track * 12) + 8 + 0x8])); if (sdlen > 0) { generate_track_from_bitstream(track / 2, track % 2, &img[data], sdlen, image); data += (sdlen + 7) >> 3; } if (ddlen > 0) { generate_track_from_bitstream(track / 2, track % 2, &img[data], ddlen, image); data += (ddlen + 7) >> 3; }
int d88_format::identify(io_generic *io, uint32_t form_factor) { uint64_t size = io_generic_size(io); uint8_t h[32]; io_generic_read(io, h, 0, 32); if((little_endianize_int32(*(uint32_t *)(h+0x1c)) == size) && (h[0x1b] == 0x00 || h[0x1b] == 0x10 || h[0x1b] == 0x20 || h[0x1b] == 0x30 || h[0x1b] == 0x40)) return 100; return 0; }
bool d88_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint8_t h[32]; io_generic_read(io, h, 0, 32); int cell_count = 0; int track_count = 0; int head_count = 0; switch(h[0x1b]) { case 0x00: cell_count = 100000; track_count = 42; head_count = 2; image->set_variant(floppy_image::DSDD); break; case 0x10: cell_count = 100000; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSQD); break; case 0x20: cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSHD); break; case 0x30: cell_count = 100000; track_count = 42; head_count = 1; image->set_variant(floppy_image::SSDD); break; case 0x40: cell_count = 100000; track_count = 82; head_count = 1; image->set_variant(floppy_image::SSQD); break; } if(!head_count) return false; uint32_t track_pos[164]; io_generic_read(io, track_pos, 32, 164*4); for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { int pos = little_endianize_int32(track_pos[track * head_count + head]); if(!pos) continue; desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; int sector_count = 1; for(int i=0; i<sector_count; i++) { uint8_t hs[16]; io_generic_read(io, hs, pos, 16); pos += 16; uint16_t size = little_endianize_int16(*(uint16_t *)(hs+14)); if(i == 0) { sector_count = little_endianize_int16(*(uint16_t *)(hs+4)); // Support broken vfman converter if(sector_count == 0x1000) sector_count = 0x10; } sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].actual_size = size; sects[i].deleted = hs[7] != 0; sects[i].bad_crc = false; if(size) { sects[i].data = sect_data + sdatapos; io_generic_read(io, sects[i].data, pos, size); pos += size; sdatapos += size; } else sects[i].data = nullptr; } build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); } return true; }
static uint32_t get_leuint32(const void *ptr) { uint32_t value; memcpy(&value, ptr, sizeof(value)); return little_endianize_int32(value); }
bool fdd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 hsec[0x0c]; // sector map UINT8 num_secs[160]; UINT8 tracks[160 * 26]; UINT8 heads[160 * 26]; UINT8 secs[160 * 26]; UINT8 fill_vals[160 * 26]; UINT32 sec_offs[160 * 26]; UINT8 sec_sizes[160 * 26]; int pos = 0xdc; for (int track = 0; track < 160; track++) { int curr_num_sec = 0, curr_track_size = 0; for (int sect = 0; sect < 26; sect++) { // read sector map for this sector io_generic_read(io, hsec, pos, 0x0c); pos += 0x0c; if (hsec[0] == 0xff) // unformatted/unused sector continue; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; fill_vals[(track * 26) + sect] = hsec[4]; sec_offs[(track * 26) + sect] = little_endianize_int32(*(UINT32 *)(hsec + 0x08)); curr_track_size += (128 << hsec[3]); curr_num_sec++; } num_secs[track] = curr_num_sec; } int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; desc_pc_sector sects[256]; UINT8 sect_data[65536]; int cur_sec_map = 0, sector_size; for (int track = 0; track < 160; track++) { int cur_pos = 0; for (int i = 0; i < num_secs[track]; i++) { cur_sec_map = track * 26 + i; sector_size = 128 << sec_sizes[cur_sec_map]; if (sec_offs[cur_sec_map] == 0xffffffff) memset(sect_data + cur_pos, fill_vals[cur_sec_map], sector_size); else io_generic_read(io, sect_data + cur_pos, sec_offs[cur_sec_map], sector_size); sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; sects[i].sector = secs[cur_sec_map]; sects[i].size = sec_sizes[cur_sec_map]; sects[i].actual_size = sector_size; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + cur_pos; cur_pos += sector_size; } build_pc_track_mfm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); } return true; }
bool nfd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint64_t size = io_generic_size(io); uint8_t h[0x120], hsec[0x10]; io_generic_read(io, h, 0, 0x120); int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; // sector map (the 164th entry is only used by rev.1 format, loops with track < 163 are correct for rev.0) uint8_t disk_type = 0; uint8_t num_secs[164]; uint8_t num_specials[164]; uint32_t track_sizes[164]; uint8_t tracks[164 * 26]; uint8_t heads[164 * 26]; uint8_t secs[164 * 26]; uint8_t mfm[164 * 26]; uint8_t sec_sizes[164 * 26]; uint32_t hsize = little_endianize_int32(*(uint32_t *)(h+0x110)); int pos = 0x120; // set up sector map if (format_version == 1) { for (int track = 0; track < 164; track++) { int curr_track_size = 0; // read sector map absolute location io_generic_read(io, hsec, pos, 4); pos += 4; uint32_t secmap_addr = little_endianize_int32(*(uint32_t *)(hsec)); if (secmap_addr) { // read actual sector map for the sectors of this track // for rev.1 format the first 0x10 are a track summary: // first WORD is # of sectors, second WORD is # of special data sectors io_generic_read(io, hsec, secmap_addr, 0x10); secmap_addr += 0x10; num_secs[track] = little_endianize_int16(*(uint16_t *)(hsec)); num_specials[track] = little_endianize_int16(*(uint16_t *)(hsec + 0x2)); for (int sect = 0; sect < num_secs[track]; sect++) { io_generic_read(io, hsec, secmap_addr, 0x10); if (track == 0 && sect == 0) disk_type = hsec[0xb]; // can this change across the disk? I don't think so... secmap_addr += 0x10; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; mfm[(track * 26) + sect] = hsec[4]; curr_track_size += (128 << hsec[3]); } if (num_specials[track] > 0) { for (int sect = 0; sect < num_specials[track]; sect++) { io_generic_read(io, hsec, secmap_addr, 0x10); secmap_addr += 0x10; curr_track_size += (hsec[9] + 1) * little_endianize_int32(*(uint32_t *)(hsec + 0x0a)); } } } else { num_secs[track] = 0; num_specials[track] = 0; } track_sizes[track] = curr_track_size; } } else { for (int track = 0; track < 163 && pos < hsize; track++) { int curr_num_sec = 0, curr_track_size = 0; for (int sect = 0; sect < 26; sect++) { // read sector map for this sector // for rev.0 format each sector uses 0x10 bytes io_generic_read(io, hsec, pos, 0x10); if (track == 0 && sect == 0) disk_type = hsec[0xa]; // can this change across the disk? I don't think so... pos += 0x10; if (hsec[0] == 0xff) // unformatted/unused sector continue; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; mfm[(track * 26) + sect] = hsec[4]; curr_track_size += (128 << hsec[3]); curr_num_sec++; } num_secs[track] = curr_num_sec; track_sizes[track] = curr_track_size; } } // shouln't this be set-up depending on disk_type? gaplus does not like having less than 166666 cells int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; switch (disk_type) { case 0x10: // 640K disk, 2DD image->set_variant(floppy_image::DSDD); break; //case 0x30: // 1.44M disk, ?? (no images found) // break; case 0x90: // 1.2M disk, 2HD default: image->set_variant(floppy_image::DSHD); break; } desc_pc_sector sects[256]; uint8_t sect_data[65536]; int cur_sec_map = 0, sector_size; pos = hsize; for (int track = 0; track < 163 && pos < size; track++) { io_generic_read(io, sect_data, pos, track_sizes[track]); for (int i = 0; i < num_secs[track]; i++) { cur_sec_map = track * 26 + i; sector_size = 128 << sec_sizes[cur_sec_map]; sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; sects[i].sector = secs[cur_sec_map]; sects[i].size = sec_sizes[cur_sec_map]; sects[i].actual_size = sector_size; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * sector_size; } pos += track_sizes[track]; // notice that the operation below might fail if sectors of the same track have variable sec_sizes, // because the gap3 calculation would account correctly only for the first sector... // examined images had constant sec_sizes in the each track, so probably this is not an issue if (mfm[track * 26]) build_pc_track_mfm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); else build_pc_track_fm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); } return true; }