2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
15 #include "../fileio.h"
18 #define local_path(x) create_local_path(x)
20 #define local_path(x) (x)
26 static const uint16_t crc_table[256] = {
27 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
28 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
29 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
30 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
31 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
32 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
33 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
34 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
35 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
36 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
37 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
38 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
39 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
40 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
41 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
42 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
45 static const int secsize[8] = {
46 128, 256, 512, 1024, 2048, 4096, 8192, 16384
49 static uint8_t tmp_buffer[DISK_BUFFER_SIZE];
51 static const fd_format_t fd_formats_base[] = {
52 { MEDIA_TYPE_2D, 35, 1, 16, 128, FM }, // 1S 70KB
53 { MEDIA_TYPE_2D, 35, 2, 16, 128, FM }, // 2S 140KB
54 { MEDIA_TYPE_2DD, 77, 1, 26, 128, FM }, // 1S 250KB
55 { MEDIA_TYPE_2D, 40, 1, 8, 512, MFM }, // 1D 160KB
56 { MEDIA_TYPE_2D, 40, 1, 9, 512, MFM }, // 1D 180KB
57 { MEDIA_TYPE_2D, 40, 1, 10, 512, MFM }, // 1D 200KB
58 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
59 // { MEDIA_TYPE_2DD, 70, 1, 8, 512, MFM }, // 1DD 280KB
60 // { MEDIA_TYPE_2DD, 70, 1, 9, 512, MFM }, // 1DD 315KB
61 // { MEDIA_TYPE_2DD, 70, 1, 10, 512, MFM }, // 1DD 350KB
62 // { MEDIA_TYPE_2DD, 80, 1, 8, 512, MFM }, // 1DD 320KB
63 // { MEDIA_TYPE_2DD, 80, 1, 9, 512, MFM }, // 1DD 360KB
64 // { MEDIA_TYPE_2DD, 80, 1, 10, 512, MFM }, // 1DD 400KB
66 { MEDIA_TYPE_2D, 35, 2, 8, 512, MFM }, // 2D 280KB
67 { MEDIA_TYPE_2D, 35, 2, 9, 512, MFM }, // 2D 315KB
68 { MEDIA_TYPE_2D, 35, 2, 10, 512, MFM }, // 2D 350KB
69 { MEDIA_TYPE_2D, 40, 2, 8, 512, MFM }, // 2D 320KB
70 { MEDIA_TYPE_2D, 40, 2, 9, 512, MFM }, // 2D 360KB
71 { MEDIA_TYPE_2D, 40, 2, 10, 512, MFM }, // 2D 400KB
73 { MEDIA_TYPE_2DD, 80, 2, 8, 512, MFM }, // 2DD 640KB
74 { MEDIA_TYPE_2DD, 80, 2, 9, 512, MFM }, // 2DD 720KB
75 { MEDIA_TYPE_2DD, 81, 2, 9, 512, MFM }, // 2DD 729KB, ASCII MSX
76 { MEDIA_TYPE_2DD, 80, 2, 10, 512, MFM }, // 2DD 800KB
77 { MEDIA_TYPE_2HD, 77, 2, 26, 256, MFM }, // 2HD 1001KB, MITSUBISHI/IBM
78 { MEDIA_TYPE_2HD, 80, 2, 15, 512, MFM }, // 2HC 1200KB, TOSHIBA/IBM
79 { MEDIA_TYPE_2HD, 77, 2, 8, 1024, MFM }, // 2HD 1232KB, NEC
80 { MEDIA_TYPE_144, 80, 2, 18, 512, MFM }, // 2HD 1440KB
81 { MEDIA_TYPE_144, 80, 2, 21, 512, MFM }, // 2HD 1680KB
82 { MEDIA_TYPE_144, 82, 2, 21, 512, MFM }, // 2HD 1722KB
83 { MEDIA_TYPE_144, 80, 2, 36, 512, MFM }, // 2ED 2880KB
87 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
89 void DISK::setup_fd_formats(void)
93 memset(fd_formats, 0, sizeof(fd_formats));
94 #if !defined(_ANY2D88)
96 if(osd->check_feature(_T("_SC3000"))) {
99 nt = { MEDIA_TYPE_2D, 40, 1, 16, 256, MFM }; // 1D 160KB
100 } else if(osd->check_feature(_T("SMC70")) || osd->check_feature(_T("_SMC777"))) {
103 nt = { MEDIA_TYPE_2DD, 70, 1, 16, 256, MFM }; // 1DD 280KB
104 } else if (osd->check_feature(_T("_X1")) || osd->check_feature(_T("_X1TWIN"))) {
107 nt = { MEDIA_TYPE_2D, 40, 2, 16, 256, MFM }; // 2D 320KB
108 } else if(osd->check_feature(_T("_X1TURBO")) || osd->check_feature(_T("_X1TURBOZ"))) {
112 nt = { MEDIA_TYPE_2D, 40, 2, 16, 256, MFM }; // 2D 320KB
113 } else if(osd->check_feature(_T("_M5"))) {
116 nt = { MEDIA_TYPE_2D, 40, 2, 18, 256, MFM }; // 2D 360KB
117 } else if(osd->check_feature(_T("_MZ80B")) || osd->check_feature(_T("_MZ2000")) ||
118 osd->check_feature(_T("_MZ2200")) || osd->check_feature(_T("_MZ2500"))) {
121 nt = { MEDIA_TYPE_2DD, 80, 2, 16, 256, MFM }; // 2DD 640KB
122 } else if (osd->check_feature(_T("_YIS"))) {
125 nt = { MEDIA_TYPE_2DD, 80, 1, 16, 256, MFM }; // 1DD 320KB
127 if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8"))) {
130 } else if(osd->check_feature(_T("_FM77_VARIANTS"))) {
134 } else if(osd->check_feature(_T("_FM77AV_VARIANTS"))) {
139 if(osd->check_feature(_T("_FM77AV40")) || osd->check_feature(_T("_FM77AV40EX")) ||
140 osd->check_feature(_T("_FM77AV40SX")) || osd->check_feature(_T("_FM77AV20")) ||
141 osd->check_feature(_T("_FM77AV20EX"))) {
142 type_fm77av_2dd = true;
145 if(osd->check_feature(_T("SUPPORT_MEDIA_TYPE_1DD"))) {
148 if(osd->check_feature(_T("_ANY2D88"))) {
156 memcpy(&fd_formats[1], fd_formats_base, sizeof(fd_formats_base));
158 memcpy(&fd_formats[0], fd_formats_base, sizeof(fd_formats_base));
162 void DISK::open(const _TCHAR* file_path, int bank)
164 // check current disk image
166 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
174 memset(buffer, 0, sizeof(buffer));
176 write_protected = false;
177 media_type = MEDIA_TYPE_UNK;
179 is_solid_image = is_fdi_image = is_1dd_image = false;
180 trim_required = false;
181 track_mfm = drive_mfm;
184 FILEIO *fio = new FILEIO();
185 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
186 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
187 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
189 file_size.d = fio->FileLength();
190 fio->Fseek(0, FILEIO_SEEK_SET);
192 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
195 for(int i = 0; i < bank; i++) {
196 fio->Fseek(offset + 0x1c, SEEK_SET);
197 offset += fio->FgetUint32_LE();
199 fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
200 file_size.d = fio->FgetUint32_LE();
201 fio->Fseek(offset, FILEIO_SEEK_SET);
202 fio->Fread(buffer, file_size.d, 1);
204 if(check_file_extension(file_path, _T(".1dd"))) {
206 media_type = MEDIA_TYPE_2DD;
208 inserted = changed = true;
209 // trim_required = true;
211 // fix sector number from big endian to little endian
212 for(int trkside = 0; trkside < 164; trkside++) {
214 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
216 if(!IS_VALID_TRACK(offset.d)) {
219 uint8_t* t = buffer + offset.d;
220 pair_t sector_num, data_size;
221 sector_num.read_2bytes_le_from(t + 4);
222 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
224 sector_num.read_2bytes_be_from(t + 4);
225 sector_num.write_2bytes_le_to(t + 4);
227 for(int i = 0; i < sector_num.sd; i++) {
229 sector_num.write_2bytes_le_to(t + 4);
231 data_size.read_2bytes_le_from(t + 14);
232 t += data_size.sd + 0x10;
235 } else if(check_file_extension(file_path, _T(".td0"))) {
238 if(teledisk_to_d88(fio)) {
239 inserted = changed = true;
240 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
243 // failed to convert the disk image
245 } else if(check_file_extension(file_path, _T(".imd"))) {
248 if(imagedisk_to_d88(fio)) {
249 inserted = changed = true;
250 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
253 // failed to convert the disk image
255 } else if(check_file_extension(file_path, _T(".dsk"))) {
258 if(cpdread_to_d88(fio)) {
259 inserted = changed = true;
260 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
263 // failed to convert the disk image
265 } else if(check_file_extension(file_path, _T(".2d")) && file_size.d == 40 * 2 * 16 * 256) {
266 // 2d image for SHARP X1 series
268 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true)) {
269 inserted = changed = is_solid_image = true;
272 // failed to convert the disk image
274 } else if(check_file_extension(file_path, _T(".img")) && file_size.d == 70 * 1 * 16 * 256) {
275 // img image for SONY SMC-70/777 series
277 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true)) {
278 inserted = changed = is_solid_image = true;
281 // failed to convert the disk image
283 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
284 // sf7 image for SEGA SC-3000 + SF-7000
286 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true)) {
287 inserted = changed = is_solid_image = true;
290 // failed to convert the disk image
294 // check solid image file format
295 bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
296 for(int i = 0;; i++) {
297 const fd_format_t *p = &fd_formats[i];
301 int len = p->ncyl * p->nside * p->nsec * p->size;
302 // 4096 bytes: FDI header ???
303 if(file_size.d == (uint32_t)(len + (is_fdi_tmp ? 4096 : 0))) {
304 fio->Fseek(0, FILEIO_SEEK_SET);
307 fio->Fread(fdi_header, 4096, 1);
311 int nside = p->nside;
314 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
316 if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
317 type = MEDIA_TYPE_2DD;
321 } else if(type_any2d88) {
322 //#elif defined(_ANY2D88)
323 if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
324 type = MEDIA_TYPE_2DD;
328 if(open_as_256 && (size == 512 || size == 1024)) {
335 // if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
336 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
337 inserted = changed = is_solid_image = true;
340 // failed to convert the disk image
348 if(fio->IsOpened()) {
354 // check loaded image
357 if(media_type == MEDIA_TYPE_UNK) {
358 if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
359 // check 1.2MB or 1.44MB
360 for(int trkside = 0; trkside < 164; trkside++) {
362 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
364 if(!IS_VALID_TRACK(offset.d)) {
368 uint8_t *t = buffer + offset.d;
369 pair_t sector_num, data_size;
370 sector_num.read_2bytes_le_from(t + 4);
371 data_size.read_2bytes_le_from(t + 14);
373 if(sector_num.sd >= 18 && data_size.sd == 512) {
374 media_type = MEDIA_TYPE_144;
381 // fix write protect flag
382 if(buffer[0x1a] != 0) {
384 write_protected = true;
387 // get crc32 for midification check
388 orig_file_size = file_size.d;
389 orig_crc32 = get_crc32(buffer, file_size.d);
391 // check special disk image
392 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
394 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
395 if(media_type == MEDIA_TYPE_2D) {
397 pair_t offset, sector_num, data_size;
398 offset.read_4bytes_le_from(buffer + 0x20);
400 if(IS_VALID_TRACK(offset.d)) {
401 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
402 uint8_t* t = buffer + offset.d;
403 sector_num.read_2bytes_le_from(t + 4);
404 for(int _i = 0; _i < sector_num.sd; _i++) {
405 data_size.read_2bytes_le_from(t + 14);
406 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
407 /* Type 1: Sec07, +$50- "1989/09/12 ... "*/
408 static const uint8_t gamblerfm_1[] = {
409 0x31, 0x39, 0x38, 0x39, 0x2f, 0x30, 0x39, 0x2f,
410 0x31, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 0x28, 0x43, 0x29, 0x47, 0x41, 0x4d, 0x45, 0x41,
412 0x52, 0x54, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
413 0x20, 0x20, 0x20, 0x59, 0x45, 0x4c, 0x4c, 0x4f,
414 0x57, 0x48, 0x4f, 0x52, 0x4e, 0x00, 0x00, 0x00,
415 0x20, 0x20, 0x20, 0x4b, 0x4f, 0x55, 0x44, 0x41,
416 0x4e, 0x53, 0x59, 0x41, 0x20, 0x59, 0x4f, 0x55,
417 0x4e, 0x47, 0x2d, 0x4d, 0x41, 0x47, 0x41, 0x5a,
418 0x49, 0x4e, 0x45, 0x00
420 /* Type 2: Sec07, +$30- */
421 static const uint8_t gamblerfm_2[] = {
422 0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7,
423 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3,
426 if(memcmp((void *)(t + 0x50), gamblerfm_1, sizeof(gamblerfm_1)) == 0) {
427 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
430 if(memcmp((void *)(t + 0x30), gamblerfm_2, sizeof(gamblerfm_2)) == 0) {
431 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
434 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
435 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
436 static const uint8_t deathforce[] ={
437 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
438 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
439 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
440 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
443 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
444 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
447 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 5 && t[3] == 1) {
448 //$00 * 16 + $00 + "Protected by N & A (SUPER HACKER COMBI)
449 //Can you found CHECK-ROUTINES ?Can you crack these protect ?
451 static const uint8_t xanadu2fm_d_1[] ={
452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 static const uint8_t xanadu2fm_d_2[] = {
456 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
457 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
458 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
459 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
460 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
461 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
462 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
463 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
464 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
465 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
466 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
467 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
468 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
469 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
471 if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
472 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
473 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
477 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 8 && t[3] == 1) {
479 static const uint8_t xanadu1fm_d_1[] = {
480 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
481 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
482 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
483 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
484 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
485 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
486 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
487 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
488 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
489 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
490 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
492 static const uint8_t xanadu1fm_d_2[] = {
493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
496 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
499 if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
500 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
501 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
505 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
506 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
507 static const uint8_t psyoblade_ipl1[] ={
508 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
509 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
510 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
511 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
512 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
513 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
517 static const uint8_t psyoblade_disk_1[] ={
518 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
519 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
520 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
521 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
523 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
524 static const uint8_t psyoblade_disk_2[] ={
525 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
526 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
527 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
529 //RIGLAS/FM: $3E - $7D
530 static const uint8_t riglas_fm[] = {
531 0x0d, 0x56, /* $3e-$3f */
532 0x44, 0x53, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, /* $40-$47 */
533 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1b, 0x02, /* $48-$4f */
534 0x1e, 0x00, 0x04, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $50-$57 */
535 0x43, 0x4f, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00, /* $58-$5f */
536 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1f, 0x03, /* $60-$67 */
537 0x03, 0x00, 0x05, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $68-$6f */
538 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x00, 0x00, /* $70-$77 */
539 0x43, 0x4d, 0x44, 0x00, 0x00, 0x03 /* $78-$7d */
541 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
542 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
544 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
545 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
546 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
549 } else if(memcmp((void *)(t + 0x3e + 0x10), riglas_fm, sizeof(riglas_fm)) == 0) {
550 is_special_disk = SPECIAL_DISK_FM7_RIGLAS;
553 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
554 static const uint8_t taiyoufm1[] = {
555 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
556 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
557 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
558 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
559 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
560 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
561 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
562 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
563 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
564 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
566 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
567 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
570 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
571 static const uint8_t taiyoufm2[] = {
572 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
573 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
574 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
575 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
576 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
577 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
578 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
579 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
581 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
582 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
586 t += data_size.sd + 0x10;
591 //#elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
592 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
593 if(media_type == MEDIA_TYPE_2D) {
596 offset.read_4bytes_le_from(buffer + 0x20);
597 if(IS_VALID_TRACK(offset.d)) {
598 // check first sector
599 static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
600 uint8_t *t = buffer + offset.d;
601 //#if defined(_X1TURBO) || defined(_X1TURBOZ)
602 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
603 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
606 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
607 is_special_disk = SPECIAL_DISK_X1_BATTEN;
622 trim_required = false;
624 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
626 if(/*!write_protected &&*/ !(file_size.d == orig_file_size && get_crc32(buffer, file_size.d) == orig_crc32)) {
628 FILEIO* fio = new FILEIO();
629 int pre_size = 0, post_size = 0;
630 uint8_t *pre_buffer = NULL, *post_buffer = NULL;
632 // is this d88 format ?
633 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
634 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
635 fio->Fseek(0, FILEIO_SEEK_END);
636 uint32_t total_size = fio->Ftell(), offset = 0;
637 for(int i = 0; i < file_bank; i++) {
638 fio->Fseek(offset + 0x1c, SEEK_SET);
639 offset += fio->FgetUint32_LE();
641 if((pre_size = offset) > 0) {
642 pre_buffer = (uint8_t *)malloc(pre_size);
643 fio->Fseek(0, FILEIO_SEEK_SET);
644 fio->Fread(pre_buffer, pre_size, 1);
646 fio->Fseek(offset + 0x1c, SEEK_SET);
647 offset += fio->FgetUint32_LE();
648 if((post_size = total_size - offset) > 0) {
649 post_buffer = (uint8_t *)malloc(post_size);
650 fio->Fseek(offset, FILEIO_SEEK_SET);
651 fio->Fread(post_buffer, post_size, 1);
657 // is this solid image and was physical formatted ?
659 bool formatted = false;
662 for(int trkside = 0; trkside < 164; trkside++) {
664 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
666 if(!IS_VALID_TRACK(offset.d)) {
669 if(solid_nside == 1 && (trkside & 1) == 1) {
674 uint8_t* t = buffer + offset.d;
675 pair_t sector_num, data_size;
676 sector_num.read_2bytes_le_from(t + 4);
678 if(sector_num.sd != solid_nsec) {
681 for(int i = 0; i < sector_num.sd; i++) {
682 data_size.read_2bytes_le_from(t + 14);
683 if(data_size.sd != solid_size) {
686 if(t[6] != (solid_mfm ? 0 : 0x40)) {
689 t += data_size.sd + 0x10;
692 if(tracks != (solid_ncyl * solid_nside)) {
696 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
697 is_solid_image = false;
701 if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
702 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
704 if(fio->IsOpened()) {
706 fio->Fwrite(pre_buffer, pre_size, 1);
710 fio->Fwrite(fdi_header, 4096, 1);
712 for(int trkside = 0; trkside < 164; trkside++) {
714 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
716 if(!IS_VALID_TRACK(offset.d)) {
719 uint8_t* t = buffer + offset.d;
720 pair_t sector_num, data_size;
721 sector_num.read_2bytes_le_from(t + 4);
723 for(int i = 0; i < sector_num.sd; i++) {
724 data_size.read_2bytes_le_from(t + 14);
725 fio->Fwrite(t + 0x10, data_size.sd, 1);
726 t += data_size.sd + 0x10;
730 fio->Fwrite(buffer, file_size.d, 1);
733 fio->Fwrite(post_buffer, post_size, 1);
747 inserted = write_protected = false;
749 sector_size.sd = sector_num.sd = 0;
754 void DISK::save_as_d88(const _TCHAR* file_path)
758 FILEIO* fio = new FILEIO();
759 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
761 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
762 for(int trk = 0; trk < 82; trk++) {
763 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
764 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
766 buffer[0x1b] = MEDIA_TYPE_2DD;
768 fio->Fwrite(buffer, file_size.d, 1);
777 bool DISK::get_track(int trk, int side)
779 sector_size.sd = sector_num.sd = 0;
780 invalid_format = false;
783 // disk not inserted or invalid media type
784 if(!(inserted && check_media_type())) {
789 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
790 if(!(0 <= trkside && trkside < 164)) {
797 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
799 if(!IS_VALID_TRACK(offset.d)) {
804 sector = buffer + offset.d;
805 sector_num.read_2bytes_le_from(sector + 4);
807 data_size.read_2bytes_le_from(sector + 14);
809 // create each sector position in track
811 if(sector_num.sd == 0) {
812 track_mfm = drive_mfm;
815 for(int i = 0; i < sector_num.sd; i++) {
816 data_size.read_2bytes_le_from(t + 14);
817 // t[6]: 0x00 = double-density, 0x40 = single-density
822 t += data_size.sd + 0x10;
825 int sync_size = track_mfm ? 12 : 6;
826 int am_size = track_mfm ? 3 : 0;
827 int gap0_size = track_mfm ? 80 : 40;
828 int gap1_size = track_mfm ? 50 : 26;
829 int gap2_size = track_mfm ? 22 : 11;
830 int gap3_size = 0, gap4_size;
832 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
834 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
835 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
836 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
838 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
839 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
840 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
844 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
845 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
846 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
848 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
849 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
850 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
855 int total = 0, valid_sector_num = 0;
857 for(int i = 0; i < sector_num.sd; i++) {
858 data_size.read_2bytes_le_from(t + 14);
859 sync_position[i] = total; // for invalid format case
860 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
861 if(data_size.sd > 0) {
862 total += sync_size + (am_size + 1);
863 total += data_size.sd + 2;
866 // if(t[2] != i + 1) {
869 t += data_size.sd + 0x10;
871 total += sync_size + (am_size + 1); // sync in preamble
874 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
876 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
878 if(gap3_size < 8 || gap4_size < 8) {
879 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
880 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
882 if(gap3_size < 8 || gap4_size < 8) {
883 gap0_size = gap1_size = gap3_size = gap4_size = 8;
884 invalid_format = true;
886 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
889 total -= sync_size + (am_size + 1);
890 for(int i = 0; i < sector_num.sd; i++) {
891 sync_position[i] *= get_track_size() - preamble_size - gap4_size;
892 sync_position[i] /= total;
896 total = preamble_size;
897 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
899 for(int i = 0; i < sector_num.sd; i++) {
900 data_size.read_2bytes_le_from(t + 14);
902 total = preamble_size + sync_position[i];
904 sync_position[i] = total;
906 am1_position[i] = total;
907 total += am_size + 1;
908 id_position[i] = total;
909 total += (4 + 2) + gap2_size;
910 if(data_size.sd > 0) {
911 total += sync_size + (am_size + 1);
912 data_position[i] = total;
913 total += data_size.sd + 2;
916 data_position[i] = total; // FIXME
918 t += data_size.sd + 0x10;
923 bool DISK::make_track(int trk, int side)
925 int track_size = get_track_size();
927 if(!get_track(trk, side)) {
928 // create a dummy track
929 for(int i = 0; i < track_size; i++) {
936 int sync_size = track_mfm ? 12 : 6;
937 int am_size = track_mfm ? 3 : 0;
938 int gap2_size = track_mfm ? 22 : 11;
939 uint8_t gap_data = track_mfm ? 0x4e : 0xff;
942 memset(track, gap_data, track_size);
943 int q = sync_position[array_length(sync_position) - 1];
946 for(int i = 0; i < sync_size; i++) {
950 for(int i = 0; i < am_size; i++) {
958 for(int i = 0; i < sector_num.sd; i++) {
960 data_size.read_2bytes_le_from(t + 14);
961 int p = sync_position[i];
964 for(int j = 0; j < sync_size; j++) {
965 if(p < track_size) track[p++] = 0x00;
968 uint16_t crc = 0xffff;
969 for(int j = 0; j < am_size; j++) {
970 if(p < track_size) track[p++] = 0xa1;
971 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
973 if(p < track_size) track[p++] = 0xfe;
974 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
976 if(p < track_size) track[p++] = t[0];
977 if(p < track_size) track[p++] = t[1];
978 if(p < track_size) track[p++] = t[2];
979 if(p < track_size) track[p++] = t[3];
980 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
981 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
982 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
983 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
984 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
985 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
987 for(int j = 0; j < gap2_size; j++) {
988 if(p < track_size) track[p++] = gap_data;
991 if(data_size.sd > 0) {
993 for(int j = 0; j < sync_size; j++) {
994 if(p < track_size) track[p++] = 0x00;
998 for(int j = 0; j < am_size; j++) {
999 if(p < track_size) track[p++] = 0xa1;
1000 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1002 uint8_t am2 = (t[7] != 0) ? 0xf8 : 0xfb;
1003 if(p < track_size) track[p++] = am2;
1004 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ am2]);
1006 for(int j = 0; j < data_size.sd; j++) {
1007 if(p < track_size) track[p++] = t[0x10 + j];
1008 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
1010 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1011 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1013 t += data_size.sd + 0x10;
1018 bool DISK::get_sector(int trk, int side, int index)
1020 sector_size.sd = sector_num.sd = 0;
1023 // disk not inserted or invalid media type
1024 if(!(inserted && check_media_type())) {
1029 if(trk == -1 && side == -1) {
1033 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1034 if(!(0 <= trkside && trkside < 164)) {
1038 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1040 if(!IS_VALID_TRACK(offset.d)) {
1045 uint8_t* t = buffer + offset.d;
1046 sector_num.read_2bytes_le_from(t + 4);
1048 if(index >= sector_num.sd) {
1053 for(int i = 0; i < index; i++) {
1055 data_size.read_2bytes_le_from(t + 14);
1056 t += data_size.sd + 0x10;
1062 void DISK::set_sector_info(uint8_t *t)
1065 int am_size = track_mfm ? 3 : 0;
1066 uint16_t crc = 0xffff;
1067 for(int i = 0; i < am_size; i++) {
1068 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1070 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1075 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1076 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1077 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1078 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1079 id[4] = (crc >> 8) & 0xff;
1080 id[5] = (crc >> 0) & 0xff;
1081 // http://www.gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1082 // t[6]: 0x00 = double-density, 0x40 = single-density
1083 // t[7]: 0x00 = normal, 0x10 = deleted mark
1084 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1086 deleted = (t[7] != 0);
1087 // if(ignore_crc()) {
1088 // addr_crc_error = false;
1089 // data_crc_error = false;
1091 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1092 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1095 sector_size.read_2bytes_le_from(t + 14);
1098 void DISK::set_deleted(bool value)
1100 if(sector != NULL) {
1101 uint8_t *t = sector - 0x10;
1102 t[7] = value ? 0x10 : 0;
1103 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1104 t[8] = (t[8] & 0x0f) | t[7];
1110 void DISK::set_data_crc_error(bool value)
1112 if(sector != NULL) {
1113 uint8_t *t = sector - 0x10;
1114 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1116 data_crc_error = value;
1119 void DISK::set_data_mark_missing()
1121 if(sector != NULL) {
1122 uint8_t *t = sector - 0x10;
1123 t[8] = (t[8] & 0x0f) | 0xf0;
1126 // addr_crc_error = false;
1127 data_crc_error = false;
1130 bool DISK::format_track(int trk, int side)
1132 // disk not inserted or invalid media type
1133 if(!(inserted && check_media_type())) {
1138 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1139 if(!(0 <= trkside && trkside < 164)) {
1143 // create new empty track
1146 trim_required = false;
1148 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1150 offset.d = DISK_BUFFER_SIZE;
1151 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1153 trim_required = true;
1155 track_mfm = drive_mfm;
1160 void DISK::insert_sector(uint8_t c, uint8_t h, uint8_t r, uint8_t n, bool deleted, bool data_crc_error, uint8_t fill_data, int length)
1162 uint8_t* t = buffer + DISK_BUFFER_SIZE;
1165 for(int i = 0; i < (sector_num.sd - 1); i++) {
1166 t[4] = sector_num.b.l;
1167 t[5] = sector_num.b.h;
1169 data_size.read_2bytes_le_from(t + 14);
1170 t += data_size.sd + 0x10;
1176 t[4] = sector_num.b.l;
1177 t[5] = sector_num.b.h;
1178 t[6] = track_mfm ? 0 : 0x40;
1179 t[7] = deleted ? 0x10 : 0;
1180 t[8] = data_crc_error ? 0xb0 : t[7];
1181 t[14] = (length >> 0) & 0xff;
1182 t[15] = (length >> 8) & 0xff;
1183 memset(t + 16, fill_data, length);
1188 void DISK::sync_buffer()
1192 trim_required = false;
1196 void DISK::trim_buffer()
1198 int max_tracks = 164;
1199 int track_limit = 164;
1200 uint32_t dest_offset = 0x2b0;
1203 memset(tmp_buffer, 0, sizeof(tmp_buffer));
1204 memcpy(tmp_buffer, buffer, 0x20);
1207 if(media_type == MEDIA_TYPE_2D) {
1210 for(int trkside = 0; trkside < 164; trkside++) {
1211 pair_t src_trk_offset;
1212 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1213 if(src_trk_offset.d != 0) {
1215 if(src_trk_offset.d < 0x2b0) {
1216 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1217 if(max_tracks > track_limit) {
1218 max_tracks = track_limit;
1222 if(src_trk_offset.d != 0x2b0) {
1223 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1224 if(max_tracks > 164) {
1225 dest_offset = 0x20 + max_tracks * 4);
1234 for(int trkside = 0; trkside < max_tracks; trkside++) {
1235 pair_t src_trk_offset;
1236 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1238 pair_t dest_trk_offset;
1239 dest_trk_offset.d = 0;
1241 if(IS_VALID_TRACK(src_trk_offset.d)) {
1242 uint8_t* t = buffer + src_trk_offset.d;
1243 pair_t sector_num, data_size;
1244 sector_num.read_2bytes_le_from(t + 4);
1245 if(sector_num.sd != 0) {
1246 dest_trk_offset.d = dest_offset;
1247 for(int i = 0; i < sector_num.sd; i++) {
1248 data_size.read_2bytes_le_from(t + 14);
1249 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1250 dest_offset += data_size.sd + 0x10;
1251 t += data_size.sd + 0x10;
1255 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1259 file_size.d = dest_offset;
1260 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1262 memset(buffer, 0, sizeof(buffer));
1263 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1268 if(drive_rpm != 0) {
1270 } else if(inserted) {
1271 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1273 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1277 int DISK::get_track_size()
1279 if(track_size != 0) {
1281 } else if(inserted) {
1282 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1284 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1288 double DISK::get_usec_per_track()
1290 return 1000000.0 / (get_rpm() / 60.0);
1293 double DISK::get_usec_per_bytes(int bytes)
1295 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1298 int DISK::get_bytes_per_usec(double usec)
1300 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1303 bool DISK::check_media_type()
1305 switch(drive_type) {
1307 if(type_fm77av_2dd) {
1308 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1310 return (media_type == MEDIA_TYPE_2D);
1312 case DRIVE_TYPE_2DD:
1313 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1314 case DRIVE_TYPE_2HD:
1315 return (media_type == MEDIA_TYPE_2HD);
1316 case DRIVE_TYPE_144:
1317 return (media_type == MEDIA_TYPE_144);
1318 case DRIVE_TYPE_UNK:
1319 return true; // always okay
1326 #define COPYBUFFER(src, size) { \
1327 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1330 memcpy(buffer + file_size.d, (src), (size)); \
1331 file_size.d += (size); \
1340 uint32_t trkptr[164];
1346 uint8_t dens, del, stat;
1351 // teledisk image decoder
1354 this teledisk image decoder is based on:
1356 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1357 LZSS coded by Haruhiko OKUMURA
1358 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1359 Edited and translated to English by Kenji RIKITAKE
1363 #define STRING_BUFFER_SIZE 4096
1364 #define LOOKAHEAD_BUFFER_SIZE 60
1366 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1367 #define TABLE_SIZE (N_CHAR * 2 - 1)
1368 #define ROOT_POSITION (TABLE_SIZE - 1)
1369 #define MAX_FREQ 0x8000
1371 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1372 static uint16_t td_ptr;
1373 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1374 static uint16_t td_ibufcnt, td_ibufndx;
1375 static uint8_t td_inbuf[512];
1376 static uint16_t td_freq[TABLE_SIZE + 1];
1377 static short td_prnt[TABLE_SIZE + N_CHAR];
1378 static short td_son[TABLE_SIZE];
1379 static uint16_t td_getbuf;
1380 static uint8_t td_getlen;
1382 static const uint8_t td_d_code[256] = {
1383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1385 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1386 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1387 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1388 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1389 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1390 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1391 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1392 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1393 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1394 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1395 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1396 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1397 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1398 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1400 static const uint8_t td_d_len[256] = {
1401 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1402 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1403 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1404 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1405 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1406 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1407 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1408 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1409 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1410 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1411 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1412 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1413 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1414 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1415 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1416 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1419 static int td_next_word(FILEIO* fio)
1421 if(td_ibufndx >= td_ibufcnt) {
1422 td_ibufndx = td_ibufcnt = 0;
1423 memset(td_inbuf, 0, 512);
1424 for(int i = 0; i < 512; i++) {
1425 int d = fio->Fgetc();
1436 while(td_getlen <= 8) {
1437 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1443 static int td_get_bit(FILEIO* fio)
1445 if(td_next_word(fio) < 0) {
1448 short i = td_getbuf;
1451 return (i < 0) ? 1 : 0;
1454 static int td_get_byte(FILEIO* fio)
1456 if(td_next_word(fio) != 0) {
1459 uint16_t i = td_getbuf;
1466 static void td_start_huff()
1469 for(i = 0; i < N_CHAR; i++) {
1471 td_son[i] = i + TABLE_SIZE;
1472 td_prnt[i + TABLE_SIZE] = i;
1475 while(j <= ROOT_POSITION) {
1476 td_freq[j] = td_freq[i] + td_freq[i + 1];
1478 td_prnt[i] = td_prnt[i + 1] = j;
1481 td_freq[TABLE_SIZE] = 0xffff;
1482 td_prnt[ROOT_POSITION] = 0;
1485 static void td_reconst()
1489 for(i = 0; i < TABLE_SIZE; i++) {
1490 if(td_son[i] >= TABLE_SIZE) {
1491 td_freq[j] = (td_freq[i] + 1) / 2;
1492 td_son[j] = td_son[i];
1496 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1498 f = td_freq[j] = td_freq[i] + td_freq[k];
1499 for(k = j - 1; f < td_freq[k]; k--);
1502 memmove(&td_freq[k + 1], &td_freq[k], l);
1504 memmove(&td_son[k + 1], &td_son[k], l);
1507 for(i = 0; i < TABLE_SIZE; i++) {
1508 if((k = td_son[i]) >= TABLE_SIZE) {
1511 td_prnt[k] = td_prnt[k + 1] = i;
1516 static void td_update(int c)
1519 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1522 c = td_prnt[c + TABLE_SIZE];
1525 if(k > td_freq[l = c + 1]) {
1526 while(k > td_freq[++l]);
1528 td_freq[c] = td_freq[l];
1532 if(i < TABLE_SIZE) {
1538 if(j < TABLE_SIZE) {
1545 while((c = td_prnt[c]) != 0);
1548 static short td_decode_char(FILEIO* fio)
1551 uint16_t c = td_son[ROOT_POSITION];
1552 while(c < TABLE_SIZE) {
1553 if((ret = td_get_bit(fio)) < 0) {
1564 static short td_decode_position(FILEIO* fio)
1568 if((bit = td_get_byte(fio)) < 0) {
1572 c = (uint16_t)td_d_code[i] << 6;
1573 j = td_d_len[i] - 2;
1575 if((bit = td_get_bit(fio)) < 0) {
1580 return (c | (i & 0x3f));
1583 static void td_init_decode()
1585 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1588 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1589 td_text_buf[i] = ' ';
1591 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1594 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1598 for(count = 0; count < len;) {
1599 if(td_bufcnt == 0) {
1600 if((c = td_decode_char(fio)) < 0) {
1604 *(buf++) = (uint8_t)c;
1605 td_text_buf[td_ptr++] = (uint8_t)c;
1606 td_ptr &= (STRING_BUFFER_SIZE - 1);
1609 if((pos = td_decode_position(fio)) < 0) {
1612 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1613 td_bufcnt = c - 255 + THRESHOLD;
1617 while(td_bufndx < td_bufcnt && count < len) {
1618 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1619 *(buf++) = (uint8_t)c;
1621 td_text_buf[td_ptr++] = (uint8_t)c;
1622 td_ptr &= (STRING_BUFFER_SIZE - 1);
1625 if(td_bufndx >= td_bufcnt) {
1626 td_bufndx = td_bufcnt = 0;
1653 uint8_t nsec, trk, head;
1662 bool DISK::teledisk_to_d88(FILEIO *fio)
1669 bool temporary = false;
1671 // check teledisk header
1672 fio->Fseek(0, FILEIO_SEEK_SET);
1673 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1674 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1675 // this image is compressed
1676 // decompress to the temporary file
1677 FILEIO* fio_tmp = new FILEIO();
1678 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1685 if((rd = td_decode(fio, obuf, 512)) > 0) {
1686 fio_tmp->Fwrite(obuf, rd, 1);
1694 // reopen the temporary file
1696 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1699 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1700 // this image is not compressed
1704 if(hdr.flag & 0x80) {
1706 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1707 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1710 // create d88 header
1714 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1715 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1716 d88_hdr.protect = 0; // non-protected
1719 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1722 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1723 fio->Fread(&trk, sizeof(td_trk_t), 1);
1724 while(trk.nsec != 0xff) {
1725 d88_hdr.trkptr[trkcnt++] = trkptr;
1726 if(hdr.sides == 1) {
1730 // read sectors in this track
1731 for(int i = 0; i < trk.nsec; i++) {
1732 uint8_t buf[2048], dst[2048];
1733 memset(buf, 0, sizeof(buf));
1734 memset(dst, 0, sizeof(dst));
1736 // read sector header
1737 fio->Fread(&sct, sizeof(td_sct_t), 1);
1739 // create d88 sector header
1740 memset(&d88_sct, 0, sizeof(d88_sct_t));
1745 d88_sct.nsec = trk.nsec;
1746 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1747 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1748 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1749 d88_sct.size = secsize[sct.n & 3];
1751 // create sector image
1752 if(sct.ctrl & 0x30) {
1753 d88_sct.stat = 0xf0; // data mark missing
1756 // read sector source
1757 int len = fio->Fgetc();
1758 len += fio->Fgetc() * 256 - 1;
1759 int flag = fio->Fgetc(), d = 0;
1760 fio->Fread(buf, len, 1);
1764 memcpy(dst, buf, len);
1765 } else if(flag == 1) {
1767 len2.read_2bytes_le_from(buf);
1772 } else if(flag == 2) {
1773 for(int s = 0; s < len;) {
1774 int type = buf[s++];
1775 int len2 = buf[s++];
1778 dst[d++] = buf[s++];
1780 } else if(type < 5) {
1786 for(int j = 0; j < n; j++) {
1790 for(int j = 0; j < n; j++) {
1795 break; // unknown type
1799 break; // unknown flag
1804 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1805 COPYBUFFER(dst, d88_sct.size);
1806 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1809 fio->Fread(&trk, sizeof(td_trk_t), 1);
1811 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1812 d88_hdr.size = trkptr;
1813 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1816 FILEIO::RemoveFile(_T("teledisk.$$$"));
1821 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1823 bool DISK::imagedisk_to_d88(FILEIO *fio)
1825 int size = fio->FileLength();
1826 fio->Fseek(0, FILEIO_SEEK_SET);
1827 fio->Fread(tmp_buffer, size, 1);
1829 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1834 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1841 // create d88 header
1845 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1846 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1847 d88_hdr.protect = 0; // non-protected
1850 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1853 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1858 // check track header
1859 uint8_t mode = tmp_buffer[pos++];
1860 uint8_t track = tmp_buffer[pos++];
1861 uint8_t head = tmp_buffer[pos++];
1862 uint8_t sector_count = tmp_buffer[pos++];
1863 uint8_t ssize = tmp_buffer[pos++];
1865 if(sector_count == 0) {
1871 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1874 const uint8_t *snum = &tmp_buffer[pos];
1875 pos += sector_count;
1876 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1878 pos += sector_count;
1879 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1881 pos += sector_count;
1885 int trkside = track * 2 + (head & 1);
1887 if(trkcnt < trkside) {
1890 d88_hdr.trkptr[trkside] = trkptr;
1892 if(img_mode == -1) {
1893 img_mode = mode & 3;
1896 // read sectors in this track
1897 for(int i = 0; i < sector_count; i++) {
1898 // create d88 sector header
1899 uint8_t stype = tmp_buffer[pos++];
1900 memset(&d88_sct, 0, sizeof(d88_sct_t));
1901 d88_sct.c = tnum ? tnum[i] : track;
1902 d88_sct.h = hnum ? hnum[i] : head;
1903 d88_sct.r = snum[i];
1905 d88_sct.nsec = sector_count;
1906 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1908 if(stype == 0 || stype > 8) {
1909 d88_sct.stat = 0xf0; // data mark missing
1912 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1913 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1914 d88_sct.size = actual_size;
1916 // create sector image
1917 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1918 memset(dst, tmp_buffer[pos++], actual_size);
1920 memcpy(dst, &tmp_buffer[pos], actual_size);
1921 pos += d88_sct.size;
1927 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1928 COPYBUFFER(dst, d88_sct.size);
1929 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1933 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1934 d88_hdr.size = trkptr;
1935 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1939 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1941 #define DSK_FORMAT_HEADER "MV - CPC"
1942 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1945 struct track_header {
1946 uint8_t headertag[13];
1949 uint8_t track_number;
1950 uint8_t side_number;
1953 uint8_t sector_size_code;
1954 uint8_t number_of_sector;
1955 uint8_t gap3_length;
1956 uint8_t filler_byte;
1958 struct sector_header {
1962 uint8_t sector_size_code;
1963 uint8_t fdc_status_reg1;
1964 uint8_t fdc_status_reg2;
1965 uint16_t data_length;
1969 bool DISK::cpdread_to_d88(FILEIO *fio)
1971 bool extendformat = false;
1972 int image_size = fio->FileLength();
1974 fio->Fseek(0, FILEIO_SEEK_SET);
1975 fio->Fread(tmp_buffer, image_size, 1);
1977 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1978 extendformat = true;
1979 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1980 extendformat = false;
1985 int heads = tmp_buffer[0x31];
1990 int tracks = tmp_buffer[0x30];
1991 int track_offsets[84 * 2];
1992 bool track_offsets_error = false;
1994 int cnt = 0, tmp = 0x100;
1995 for(int i = 0; i < tracks * heads; i++) {
1996 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1997 if(track_offsets_error) {
2000 track_offsets[cnt] = tmp;
2001 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
2005 int cnt = 0, tmp = 0x100;
2006 for(int i = 0; i < tracks * heads; i++) {
2007 int length = tmp_buffer[0x34 + i] << 8;
2009 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2010 if(track_offsets_error) {
2013 track_offsets[cnt] = tmp;
2016 track_offsets[cnt] = image_size;
2021 if(track_offsets_error) {
2022 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
2023 // so I modified this code to search "Track-Info" at the top of track information block
2024 int cnt = 0, tmp = 0x100;
2025 for(int i = 0; i < tracks * heads; i++) {
2027 for(; tmp < image_size; tmp += 0x10) {
2028 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
2034 track_offsets[cnt] = tmp;
2037 track_offsets[cnt] = image_size;
2043 // create d88 header
2047 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2048 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
2049 d88_hdr.protect = 0; // non-protected
2052 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2055 int total = 0, trkptr = sizeof(d88_hdr_t);
2057 for(int track = 0; track < tracks; track++) {
2058 for(int side = 0; side < heads; side++) {
2059 if(track_offsets[(track << 1) + side] >= image_size) {
2062 if((track << 1) + side < 164) {
2063 d88_hdr.trkptr[(track << 1) + side] = trkptr;
2067 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
2068 int pos = track_offsets[(track << 1) + side] + 0x100;
2069 for(int j = 0; j < tr.number_of_sector; j++) {
2070 sector_header sector;
2071 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2073 // create d88 sector header
2074 memset(&d88_sct, 0, sizeof(d88_sct_t));
2075 d88_sct.c = sector.track;
2076 d88_sct.h = sector.side;
2077 d88_sct.r = sector.sector_id;
2078 d88_sct.n = sector.sector_size_code;
2079 d88_sct.nsec = tr.number_of_sector;
2081 d88_sct.size = sector.data_length;
2082 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2084 d88_sct.size = 128 << tr.sector_size_code;
2085 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2087 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2088 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2091 if((track << 1) + side < 164) {
2092 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2093 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2094 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2096 total += d88_sct.size;
2099 pos += sector.data_length;
2101 pos += 128 << tr.sector_size_code;
2106 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2107 d88_hdr.size = trkptr;
2108 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2112 // solid image decoder
2114 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2120 solid_nside = nside;
2125 // create d88 header
2129 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2130 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2131 d88_hdr.protect = 0; // non-protected
2134 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2137 for(int i = 0; i < 8; i++) {
2138 if(size == (128 << i)) {
2145 int trkptr = sizeof(d88_hdr_t);
2147 for(int c = 0; c < ncyl; c++) {
2148 for(int h = 0; h < nside; h++) {
2149 d88_hdr.trkptr[t++] = trkptr;
2154 // read sectors in this track
2155 for(int s = 0; s < nsec; s++) {
2156 // create d88 sector header
2157 memset(&d88_sct, 0, sizeof(d88_sct_t));
2162 d88_sct.nsec = nsec;
2166 d88_sct.size = size;
2168 // create sector image
2170 memset(dst, 0xe5, sizeof(dst));
2171 fio->Fread(dst, size, 1);
2174 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2175 COPYBUFFER(dst, size);
2176 trkptr += sizeof(d88_sct_t) + size;
2180 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2181 d88_hdr.size = trkptr;
2182 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2186 #define STATE_VERSION 13
2188 void DISK::save_state(FILEIO* state_fio)
2190 state_fio->FputUint32(STATE_VERSION);
2192 state_fio->Fwrite(buffer, sizeof(buffer), 1);
2193 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2194 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2195 state_fio->FputUint32(file_size.d);
2196 state_fio->FputInt32(file_bank);
2197 state_fio->FputUint32(orig_file_size);
2198 state_fio->FputUint32(orig_crc32);
2199 state_fio->FputBool(trim_required);
2200 state_fio->FputBool(is_1dd_image);
2201 state_fio->FputBool(is_solid_image);
2202 state_fio->FputBool(is_fdi_image);
2203 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2204 state_fio->FputInt32(solid_ncyl);
2205 state_fio->FputInt32(solid_nside);
2206 state_fio->FputInt32(solid_nsec);
2207 state_fio->FputInt32(solid_size);
2208 state_fio->FputBool(solid_mfm);
2209 state_fio->FputBool(inserted);
2210 state_fio->FputBool(ejected);
2211 state_fio->FputBool(write_protected);
2212 state_fio->FputBool(changed);
2213 state_fio->FputUint8(media_type);
2214 state_fio->FputInt32(is_special_disk);
2215 state_fio->Fwrite(track, sizeof(track), 1);
2216 state_fio->FputInt32(sector_num.sd);
2217 state_fio->FputBool(track_mfm);
2218 state_fio->FputBool(invalid_format);
2219 // state_fio->FputBool(no_skew);
2220 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2221 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2222 state_fio->Fwrite(id_position, sizeof(id_position), 1);
2223 state_fio->Fwrite(data_position, sizeof(data_position), 1);
2224 // state_fio->FputInt32(gap3_size);
2225 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2226 state_fio->FputInt32(sector_size.sd);
2227 state_fio->Fwrite(id, sizeof(id), 1);
2228 state_fio->FputUint8(density);
2229 state_fio->FputBool(deleted);
2230 state_fio->FputBool(addr_crc_error);
2231 state_fio->FputBool(data_crc_error);
2232 state_fio->FputUint8(drive_type);
2233 state_fio->FputInt32(drive_rpm);
2234 state_fio->FputBool(drive_mfm);
2237 bool DISK::load_state(FILEIO* state_fio)
2239 if(state_fio->FgetUint32() != STATE_VERSION) {
2242 state_fio->Fread(buffer, sizeof(buffer), 1);
2243 state_fio->Fread(orig_path, sizeof(orig_path), 1);
2244 state_fio->Fread(dest_path, sizeof(dest_path), 1);
2245 file_size.d = state_fio->FgetUint32();
2246 file_bank = state_fio->FgetInt32();
2247 orig_file_size = state_fio->FgetUint32();
2248 orig_crc32 = state_fio->FgetUint32();
2249 trim_required = state_fio->FgetBool();
2250 is_1dd_image = state_fio->FgetBool();
2251 is_solid_image = state_fio->FgetBool();
2252 is_fdi_image = state_fio->FgetBool();
2253 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2254 solid_ncyl = state_fio->FgetInt32();
2255 solid_nside = state_fio->FgetInt32();
2256 solid_nsec = state_fio->FgetInt32();
2257 solid_size = state_fio->FgetInt32();
2258 solid_mfm = state_fio->FgetBool();
2259 inserted = state_fio->FgetBool();
2260 ejected = state_fio->FgetBool();
2261 write_protected = state_fio->FgetBool();
2262 changed = state_fio->FgetBool();
2263 media_type = state_fio->FgetUint8();
2264 is_special_disk = state_fio->FgetInt32();
2265 state_fio->Fread(track, sizeof(track), 1);
2266 sector_num.sd = state_fio->FgetInt32();
2267 track_mfm = state_fio->FgetBool();
2268 invalid_format = state_fio->FgetBool();
2269 // no_skew = state_fio->FgetBool();
2270 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2271 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2272 state_fio->Fread(id_position, sizeof(id_position), 1);
2273 state_fio->Fread(data_position, sizeof(data_position), 1);
2274 // gap3_size = state_fio->FgetInt32();
2275 int offset = state_fio->FgetInt32();
2276 sector = (offset != -1) ? buffer + offset : NULL;
2277 sector_size.sd = state_fio->FgetInt32();
2278 state_fio->Fread(id, sizeof(id), 1);
2279 density = state_fio->FgetUint8();
2280 deleted = state_fio->FgetBool();
2281 addr_crc_error = state_fio->FgetBool();
2282 data_crc_error = state_fio->FgetBool();
2283 drive_type = state_fio->FgetUint8();
2284 drive_rpm = state_fio->FgetInt32();
2285 drive_mfm = state_fio->FgetBool();