bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { 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); head_count = header[9]; if(header[0] == 't') { td0dsk_t disk_decode; disk_decode.floppy_file = io; disk_decode.init_Decode(); disk_decode.floppy_file_offset = 12; disk_decode.Decode(&imagebuf[0], max_size); } else io_generic_read(io, &imagebuf[0], 12, io_generic_size(io)); if(header[7] & 0x80) offset = 10 + imagebuf[2] + (imagebuf[3] << 8); track_spt = imagebuf[offset]; if(track_spt == 255) // Empty file? return false; switch(header[6]) { case 2: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) 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 */ case 1: if(head_count == 2) image->set_variant(floppy_image::DSDD); else 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); else return false; // single side 3.5? break; } else image->set_variant(floppy_image::SSDD); break; /* no break */ case 3: if(head_count == 2) { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::DSQD); else image->set_variant(floppy_image::DSDD); } else { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::SSQD); else return false; // single side 3.5? } break; } static const int rates[3] = { 250000, 300000, 500000 }; int rate = (header[5] & 0x7f) >= 3 ? 500000 : rates[header[5] & 0x7f]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; while(track_spt != 255) { desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; int track = imagebuf[offset + 1]; int head = imagebuf[offset + 2] & 1; bool fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); // ? offset += 4; for(int i = 0; i < track_spt; i++) { uint8_t *hs = &imagebuf[offset]; uint16_t size; offset += 6; sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].deleted = (hs[4] & 4) == 4; sects[i].bad_crc = (hs[4] & 2) == 2; if(hs[4] & 0x30) size = 0; else { offset += 3; size = 128 << hs[3]; int j, k; switch(hs[8]) { default: return false; case 0: memcpy(§_data[sdatapos], &imagebuf[offset], size); offset += size; break; case 1: offset += 4; k = (hs[9] + (hs[10] << 8)) * 2; k = (k <= size) ? k : size; for(j = 0; j < k; j += 2) { sect_data[sdatapos + j] = hs[11]; sect_data[sdatapos + j + 1] = hs[12]; } if(k < size) memset(§_data[sdatapos + k], '\0', size - k); break; case 2: k = 0; while(k < size) { uint16_t len = imagebuf[offset]; uint16_t rep = imagebuf[offset + 1]; offset += 2; if(!len) { memcpy(§_data[sdatapos + k], &imagebuf[offset], rep); offset += rep; k += rep; } else { len = (1 << len); rep = len * rep; rep = ((rep + k) <= size) ? rep : (size - k); for(j = 0; j < rep; j += len) memcpy(§_data[sdatapos + j + k], &imagebuf[offset], len); k += rep; offset += len; } } break; } } sects[i].actual_size = size; if(size) { sects[i].data = §_data[sdatapos]; sdatapos += size; } else sects[i].data = nullptr; } track_count = track; if(fm) build_pc_track_fm(track, head, image, base_cell_count, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); 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)); 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); } return true; }
bool cqm_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy dynamic_buffer imagebuf(max_size); UINT8 header[CQM_HEADER_SIZE]; io_generic_read(io, header, 0, CQM_HEADER_SIZE); int sector_size = (header[0x04] << 8) | header[0x03]; int sector_per_track = (header[0x11] << 8) | header[0x10]; int heads = (header[0x13] << 8) | header[0x12]; int tracks = header[0x5b]; // int blind = header[0x58]; // 0=DOS, 1=blind, 2=HFS int density = header[0x59]; // 0=DD, 1=HD, 2=ED int comment_size = (header[0x70] << 8) | header[0x6f]; int sector_base = header[0x71] + 1; // int interleave = header[0x74]; // TODO // int skew = header[0x75]; // TODO // int drive = header[0x76]; // source drive type: 1=5.25" 360KB, 2=5.25" 1.2MB, 3=3.5" 720KB, 4=3.5" 1.44MB, 6=3.5" 2.88MB, 8" is unknown (0 or 5?) switch(density) { case 0: if (form_factor == floppy_image::FF_525 && tracks > 50) image->set_variant(heads == 1 ? floppy_image::SSQD : floppy_image::DSQD); else image->set_variant(heads == 1 ? floppy_image::SSDD : floppy_image::DSDD); break; case 1: if (heads == 1) return false; // single side HD ? image->set_variant(floppy_image::DSHD); break; case 2: if (heads == 1) return false; // single side ED ? image->set_variant(floppy_image::DSED); default: return false; } static const int rates[3] = { 250000, 300000, 500000 }; int rate = density >= 3 ? 500000 : rates[density]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; int cqm_size = io_generic_size(io); dynamic_buffer cqmbuf(cqm_size); io_generic_read(io, &cqmbuf[0], 0, cqm_size); // decode the RLE data for (int s = 0, pos = CQM_HEADER_SIZE + comment_size; pos < cqm_size; ) { INT16 len = (cqmbuf[pos + 1] << 8) | cqmbuf[pos]; pos += 2; if(len < 0) { len = -len; memset(&imagebuf[s], cqmbuf[pos], len); pos++; } else { memcpy(&imagebuf[s], &cqmbuf[pos], len); pos += len; } s += len; } int ssize; for(ssize=0; (128 << ssize) < sector_size; ssize++) ; desc_pc_sector sects[256]; for(int track = 0, pos = 0; track < tracks; track++) for(int head = 0; head < heads; head++) { for(int sector = 0; sector < sector_per_track; sector++) { sects[sector].track = track; sects[sector].head = head; sects[sector].sector = sector_base + sector; sects[sector].size = ssize; sects[sector].deleted = false; sects[sector].bad_crc = false; sects[sector].actual_size = sector_size; sects[sector].data = &imagebuf[pos]; pos += sector_size; } build_pc_track_mfm(track, head, image, base_cell_count*2, sector_per_track, sects, calc_default_pc_gap3_size(form_factor, sector_size)); } return true; }