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);
399 if(IS_VALID_TRACK(offset.d)) {
400 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
401 uint8_t* t = buffer + offset.d;
402 sector_num.read_2bytes_le_from(t + 4);
403 for(int i = 0; i < sector_num.sd; i++) {
404 data_size.read_2bytes_le_from(t + 14);
405 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
406 static const uint8_t gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
407 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
408 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
411 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
412 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
413 static const uint8_t deathforce[] ={
414 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
415 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
416 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
417 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
420 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
421 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
424 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 5 && t[3] == 1) {
425 //$00 * 16 + $00 + "Protected by N & A (SUPER HACKER COMBI)
426 //Can you found CHECK-ROUTINES ?Can you crack these protect ?
428 static const uint8_t xanadu2fm_d_1[] ={
429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432 static const uint8_t xanadu2fm_d_2[] = {
433 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
434 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
435 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
436 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
437 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
438 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
439 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
440 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
441 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
442 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
443 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
444 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
445 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
446 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
448 if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
449 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
450 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
454 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 8 && t[3] == 1) {
456 static const uint8_t xanadu1fm_d_1[] = {
457 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
458 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
459 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
460 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
461 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
462 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
463 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
464 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
465 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
466 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
467 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
469 static const uint8_t xanadu1fm_d_2[] = {
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
473 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
476 if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
477 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
478 is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
482 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
483 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
484 static const uint8_t psyoblade_ipl1[] ={
485 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
486 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
487 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
488 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
489 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
490 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
494 static const uint8_t psyoblade_disk_1[] ={
495 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
496 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
497 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
498 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
500 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
501 static const uint8_t psyoblade_disk_2[] ={
502 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
503 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
504 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
506 //RIGLAS/FM: $3E - $7D
507 static const uint8_t riglas_fm[] = {
508 0x0d, 0x56, /* $3e-$3f */
509 0x44, 0x53, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, /* $40-$47 */
510 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1b, 0x02, /* $48-$4f */
511 0x1e, 0x00, 0x04, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $50-$57 */
512 0x43, 0x4f, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00, /* $58-$5f */
513 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1f, 0x03, /* $60-$67 */
514 0x03, 0x00, 0x05, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $68-$6f */
515 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x00, 0x00, /* $70-$77 */
516 0x43, 0x4d, 0x44, 0x00, 0x00, 0x03 /* $78-$7d */
518 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
519 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
521 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
522 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
523 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
526 } else if(memcmp((void *)(t + 0x3e + 0x10), riglas_fm, sizeof(riglas_fm)) == 0) {
527 is_special_disk = SPECIAL_DISK_FM7_RIGLAS;
530 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
531 static const uint8_t taiyoufm1[] = {
532 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
533 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
534 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
535 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
536 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
537 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
538 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
539 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
540 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
541 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
543 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
544 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
547 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
548 static const uint8_t taiyoufm2[] = {
549 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
550 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
551 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
552 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
553 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
554 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
555 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
556 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
558 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
559 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
563 t += data_size.sd + 0x10;
568 //#elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
569 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
570 if(media_type == MEDIA_TYPE_2D) {
573 offset.read_4bytes_le_from(buffer + 0x20);
574 if(IS_VALID_TRACK(offset.d)) {
575 // check first sector
576 static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
577 uint8_t *t = buffer + offset.d;
578 //#if defined(_X1TURBO) || defined(_X1TURBOZ)
579 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
580 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
583 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
584 is_special_disk = SPECIAL_DISK_X1_BATTEN;
599 trim_required = false;
601 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
603 if(/*!write_protected &&*/ !(file_size.d == orig_file_size && get_crc32(buffer, file_size.d) == orig_crc32)) {
605 FILEIO* fio = new FILEIO();
606 int pre_size = 0, post_size = 0;
607 uint8_t *pre_buffer = NULL, *post_buffer = NULL;
609 // is this d88 format ?
610 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
611 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
612 fio->Fseek(0, FILEIO_SEEK_END);
613 uint32_t total_size = fio->Ftell(), offset = 0;
614 for(int i = 0; i < file_bank; i++) {
615 fio->Fseek(offset + 0x1c, SEEK_SET);
616 offset += fio->FgetUint32_LE();
618 if((pre_size = offset) > 0) {
619 pre_buffer = (uint8_t *)malloc(pre_size);
620 fio->Fseek(0, FILEIO_SEEK_SET);
621 fio->Fread(pre_buffer, pre_size, 1);
623 fio->Fseek(offset + 0x1c, SEEK_SET);
624 offset += fio->FgetUint32_LE();
625 if((post_size = total_size - offset) > 0) {
626 post_buffer = (uint8_t *)malloc(post_size);
627 fio->Fseek(offset, FILEIO_SEEK_SET);
628 fio->Fread(post_buffer, post_size, 1);
634 // is this solid image and was physical formatted ?
636 bool formatted = false;
639 for(int trkside = 0; trkside < 164; trkside++) {
641 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
643 if(!IS_VALID_TRACK(offset.d)) {
646 if(solid_nside == 1 && (trkside & 1) == 1) {
651 uint8_t* t = buffer + offset.d;
652 pair_t sector_num, data_size;
653 sector_num.read_2bytes_le_from(t + 4);
655 if(sector_num.sd != solid_nsec) {
658 for(int i = 0; i < sector_num.sd; i++) {
659 data_size.read_2bytes_le_from(t + 14);
660 if(data_size.sd != solid_size) {
663 if(t[6] != (solid_mfm ? 0 : 0x40)) {
666 t += data_size.sd + 0x10;
669 if(tracks != (solid_ncyl * solid_nside)) {
673 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
674 is_solid_image = false;
678 if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
679 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
681 if(fio->IsOpened()) {
683 fio->Fwrite(pre_buffer, pre_size, 1);
687 fio->Fwrite(fdi_header, 4096, 1);
689 for(int trkside = 0; trkside < 164; trkside++) {
691 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
693 if(!IS_VALID_TRACK(offset.d)) {
696 uint8_t* t = buffer + offset.d;
697 pair_t sector_num, data_size;
698 sector_num.read_2bytes_le_from(t + 4);
700 for(int i = 0; i < sector_num.sd; i++) {
701 data_size.read_2bytes_le_from(t + 14);
702 fio->Fwrite(t + 0x10, data_size.sd, 1);
703 t += data_size.sd + 0x10;
707 fio->Fwrite(buffer, file_size.d, 1);
710 fio->Fwrite(post_buffer, post_size, 1);
724 inserted = write_protected = false;
726 sector_size.sd = sector_num.sd = 0;
731 void DISK::save_as_d88(const _TCHAR* file_path)
735 FILEIO* fio = new FILEIO();
736 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
738 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
739 for(int trk = 0; trk < 82; trk++) {
740 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
741 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
743 buffer[0x1b] = MEDIA_TYPE_2DD;
745 fio->Fwrite(buffer, file_size.d, 1);
754 bool DISK::get_track(int trk, int side)
756 sector_size.sd = sector_num.sd = 0;
757 invalid_format = false;
760 // disk not inserted or invalid media type
761 if(!(inserted && check_media_type())) {
766 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
767 if(!(0 <= trkside && trkside < 164)) {
774 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
776 if(!IS_VALID_TRACK(offset.d)) {
781 sector = buffer + offset.d;
782 sector_num.read_2bytes_le_from(sector + 4);
784 data_size.read_2bytes_le_from(sector + 14);
786 // create each sector position in track
788 if(sector_num.sd == 0) {
789 track_mfm = drive_mfm;
792 for(int i = 0; i < sector_num.sd; i++) {
793 data_size.read_2bytes_le_from(t + 14);
794 // t[6]: 0x00 = double-density, 0x40 = single-density
799 t += data_size.sd + 0x10;
802 int sync_size = track_mfm ? 12 : 6;
803 int am_size = track_mfm ? 3 : 0;
804 int gap0_size = track_mfm ? 80 : 40;
805 int gap1_size = track_mfm ? 50 : 26;
806 int gap2_size = track_mfm ? 22 : 11;
807 int gap3_size = 0, gap4_size;
809 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
811 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
812 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
813 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
815 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
816 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
817 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
821 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
822 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
823 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
825 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
826 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
827 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
832 int total = 0, valid_sector_num = 0;
834 for(int i = 0; i < sector_num.sd; i++) {
835 data_size.read_2bytes_le_from(t + 14);
836 sync_position[i] = total; // for invalid format case
837 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
838 if(data_size.sd > 0) {
839 total += sync_size + (am_size + 1);
840 total += data_size.sd + 2;
843 // if(t[2] != i + 1) {
846 t += data_size.sd + 0x10;
848 total += sync_size + (am_size + 1); // sync in preamble
851 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
853 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
855 if(gap3_size < 8 || gap4_size < 8) {
856 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
857 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
859 if(gap3_size < 8 || gap4_size < 8) {
860 gap0_size = gap1_size = gap3_size = gap4_size = 8;
861 invalid_format = true;
863 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
866 total -= sync_size + (am_size + 1);
867 for(int i = 0; i < sector_num.sd; i++) {
868 sync_position[i] *= get_track_size() - preamble_size - gap4_size;
869 sync_position[i] /= total;
873 total = preamble_size;
874 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
876 for(int i = 0; i < sector_num.sd; i++) {
877 data_size.read_2bytes_le_from(t + 14);
879 total = preamble_size + sync_position[i];
881 sync_position[i] = total;
883 am1_position[i] = total;
884 total += am_size + 1;
885 id_position[i] = total;
886 total += (4 + 2) + gap2_size;
887 if(data_size.sd > 0) {
888 total += sync_size + (am_size + 1);
889 data_position[i] = total;
890 total += data_size.sd + 2;
893 data_position[i] = total; // FIXME
895 t += data_size.sd + 0x10;
900 bool DISK::make_track(int trk, int side)
902 int track_size = get_track_size();
904 if(!get_track(trk, side)) {
905 // create a dummy track
906 for(int i = 0; i < track_size; i++) {
913 int sync_size = track_mfm ? 12 : 6;
914 int am_size = track_mfm ? 3 : 0;
915 int gap2_size = track_mfm ? 22 : 11;
916 uint8_t gap_data = track_mfm ? 0x4e : 0xff;
919 memset(track, gap_data, track_size);
920 int q = sync_position[array_length(sync_position) - 1];
923 for(int i = 0; i < sync_size; i++) {
927 for(int i = 0; i < am_size; i++) {
935 for(int i = 0; i < sector_num.sd; i++) {
937 data_size.read_2bytes_le_from(t + 14);
938 int p = sync_position[i];
941 for(int j = 0; j < sync_size; j++) {
942 if(p < track_size) track[p++] = 0x00;
945 for(int j = 0; j < am_size; j++) {
946 if(p < track_size) track[p++] = 0xa1;
948 if(p < track_size) track[p++] = 0xfe;
950 if(p < track_size) track[p++] = t[0];
951 if(p < track_size) track[p++] = t[1];
952 if(p < track_size) track[p++] = t[2];
953 if(p < track_size) track[p++] = t[3];
955 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
956 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
957 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
958 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
959 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
960 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
962 for(int j = 0; j < gap2_size; j++) {
963 if(p < track_size) track[p++] = gap_data;
966 if(data_size.sd > 0) {
968 for(int j = 0; j < sync_size; j++) {
969 if(p < track_size) track[p++] = 0x00;
972 for(int j = 0; j < am_size; j++) {
973 if(p < track_size) track[p++] = 0xa1;
975 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
978 for(int j = 0; j < data_size.sd; j++) {
979 if(p < track_size) track[p++] = t[0x10 + j];
980 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
982 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
983 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
985 t += data_size.sd + 0x10;
990 bool DISK::get_sector(int trk, int side, int index)
992 sector_size.sd = sector_num.sd = 0;
995 // disk not inserted or invalid media type
996 if(!(inserted && check_media_type())) {
1001 if(trk == -1 && side == -1) {
1005 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1006 if(!(0 <= trkside && trkside < 164)) {
1010 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1012 if(!IS_VALID_TRACK(offset.d)) {
1017 uint8_t* t = buffer + offset.d;
1018 sector_num.read_2bytes_le_from(t + 4);
1020 if(index >= sector_num.sd) {
1025 for(int i = 0; i < index; i++) {
1027 data_size.read_2bytes_le_from(t + 14);
1028 t += data_size.sd + 0x10;
1034 void DISK::set_sector_info(uint8_t *t)
1042 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1043 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1044 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1045 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1046 id[4] = (crc >> 8) & 0xff;
1047 id[5] = (crc >> 0) & 0xff;
1048 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1049 // t[6]: 0x00 = double-density, 0x40 = single-density
1050 // t[7]: 0x00 = normal, 0x10 = deleted mark
1051 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1053 deleted = (t[7] != 0);
1054 // if(ignore_crc()) {
1055 // addr_crc_error = false;
1056 // data_crc_error = false;
1058 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1059 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1062 sector_size.read_2bytes_le_from(t + 14);
1065 void DISK::set_deleted(bool value)
1067 if(sector != NULL) {
1068 uint8_t *t = sector - 0x10;
1069 t[7] = value ? 0x10 : 0;
1070 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1071 t[8] = (t[8] & 0x0f) | t[7];
1077 void DISK::set_data_crc_error(bool value)
1079 if(sector != NULL) {
1080 uint8_t *t = sector - 0x10;
1081 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1083 data_crc_error = value;
1086 void DISK::set_data_mark_missing()
1088 if(sector != NULL) {
1089 uint8_t *t = sector - 0x10;
1090 t[8] = (t[8] & 0x0f) | 0xf0;
1093 // addr_crc_error = false;
1094 data_crc_error = false;
1097 bool DISK::format_track(int trk, int side)
1099 // disk not inserted or invalid media type
1100 if(!(inserted && check_media_type())) {
1105 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1106 if(!(0 <= trkside && trkside < 164)) {
1110 // create new empty track
1113 trim_required = false;
1115 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1117 offset.d = DISK_BUFFER_SIZE;
1118 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1120 trim_required = true;
1122 track_mfm = drive_mfm;
1127 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)
1129 uint8_t* t = buffer + DISK_BUFFER_SIZE;
1132 for(int i = 0; i < (sector_num.sd - 1); i++) {
1133 t[4] = sector_num.b.l;
1134 t[5] = sector_num.b.h;
1136 data_size.read_2bytes_le_from(t + 14);
1137 t += data_size.sd + 0x10;
1143 t[4] = sector_num.b.l;
1144 t[5] = sector_num.b.h;
1145 t[6] = track_mfm ? 0 : 0x40;
1146 t[7] = deleted ? 0x10 : 0;
1147 t[8] = data_crc_error ? 0xb0 : t[7];
1148 t[14] = (length >> 0) & 0xff;
1149 t[15] = (length >> 8) & 0xff;
1150 memset(t + 16, fill_data, length);
1155 void DISK::sync_buffer()
1159 trim_required = false;
1163 void DISK::trim_buffer()
1165 int max_tracks = 164;
1166 int track_limit = 164;
1167 uint32_t dest_offset = 0x2b0;
1170 memset(tmp_buffer, 0, sizeof(tmp_buffer));
1171 memcpy(tmp_buffer, buffer, 0x20);
1174 if(media_type == MEDIA_TYPE_2D) {
1177 for(int trkside = 0; trkside < 164; trkside++) {
1178 pair_t src_trk_offset;
1179 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1180 if(src_trk_offset.d != 0) {
1182 if(src_trk_offset.d < 0x2b0) {
1183 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1184 if(max_tracks > track_limit) {
1185 max_tracks = track_limit;
1189 if(src_trk_offset.d != 0x2b0) {
1190 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1191 if(max_tracks > 164) {
1192 dest_offset = 0x20 + max_tracks * 4);
1201 for(int trkside = 0; trkside < max_tracks; trkside++) {
1202 pair_t src_trk_offset;
1203 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1205 pair_t dest_trk_offset;
1206 dest_trk_offset.d = 0;
1208 if(IS_VALID_TRACK(src_trk_offset.d)) {
1209 uint8_t* t = buffer + src_trk_offset.d;
1210 pair_t sector_num, data_size;
1211 sector_num.read_2bytes_le_from(t + 4);
1212 if(sector_num.sd != 0) {
1213 dest_trk_offset.d = dest_offset;
1214 for(int i = 0; i < sector_num.sd; i++) {
1215 data_size.read_2bytes_le_from(t + 14);
1216 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1217 dest_offset += data_size.sd + 0x10;
1218 t += data_size.sd + 0x10;
1222 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1226 file_size.d = dest_offset;
1227 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1229 memset(buffer, 0, sizeof(buffer));
1230 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1235 if(drive_rpm != 0) {
1237 } else if(inserted) {
1238 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1240 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1244 int DISK::get_track_size()
1246 if(track_size != 0) {
1248 } else if(inserted) {
1249 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1251 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1255 double DISK::get_usec_per_track()
1257 return 1000000.0 / (get_rpm() / 60.0);
1260 double DISK::get_usec_per_bytes(int bytes)
1262 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1265 int DISK::get_bytes_per_usec(double usec)
1267 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1270 bool DISK::check_media_type()
1272 switch(drive_type) {
1274 if(type_fm77av_2dd) {
1275 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1277 return (media_type == MEDIA_TYPE_2D);
1279 case DRIVE_TYPE_2DD:
1280 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1281 case DRIVE_TYPE_2HD:
1282 return (media_type == MEDIA_TYPE_2HD);
1283 case DRIVE_TYPE_144:
1284 return (media_type == MEDIA_TYPE_144);
1285 case DRIVE_TYPE_UNK:
1286 return true; // always okay
1293 #define COPYBUFFER(src, size) { \
1294 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1297 memcpy(buffer + file_size.d, (src), (size)); \
1298 file_size.d += (size); \
1307 uint32_t trkptr[164];
1313 uint8_t dens, del, stat;
1318 // teledisk image decoder
1321 this teledisk image decoder is based on:
1323 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1324 LZSS coded by Haruhiko OKUMURA
1325 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1326 Edited and translated to English by Kenji RIKITAKE
1330 #define STRING_BUFFER_SIZE 4096
1331 #define LOOKAHEAD_BUFFER_SIZE 60
1333 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1334 #define TABLE_SIZE (N_CHAR * 2 - 1)
1335 #define ROOT_POSITION (TABLE_SIZE - 1)
1336 #define MAX_FREQ 0x8000
1338 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1339 static uint16_t td_ptr;
1340 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1341 static uint16_t td_ibufcnt, td_ibufndx;
1342 static uint8_t td_inbuf[512];
1343 static uint16_t td_freq[TABLE_SIZE + 1];
1344 static short td_prnt[TABLE_SIZE + N_CHAR];
1345 static short td_son[TABLE_SIZE];
1346 static uint16_t td_getbuf;
1347 static uint8_t td_getlen;
1349 static const uint8_t td_d_code[256] = {
1350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1352 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1353 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1354 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1355 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1356 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1357 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1358 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1359 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1360 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1361 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1362 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1363 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1364 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1365 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1367 static const uint8_t td_d_len[256] = {
1368 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1369 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1370 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1371 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1372 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1373 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1374 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1375 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1376 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1377 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1378 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1379 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1380 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1381 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1382 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1383 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1386 static int td_next_word(FILEIO* fio)
1388 if(td_ibufndx >= td_ibufcnt) {
1389 td_ibufndx = td_ibufcnt = 0;
1390 memset(td_inbuf, 0, 512);
1391 for(int i = 0; i < 512; i++) {
1392 int d = fio->Fgetc();
1403 while(td_getlen <= 8) {
1404 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1410 static int td_get_bit(FILEIO* fio)
1412 if(td_next_word(fio) < 0) {
1415 short i = td_getbuf;
1418 return (i < 0) ? 1 : 0;
1421 static int td_get_byte(FILEIO* fio)
1423 if(td_next_word(fio) != 0) {
1426 uint16_t i = td_getbuf;
1433 static void td_start_huff()
1436 for(i = 0; i < N_CHAR; i++) {
1438 td_son[i] = i + TABLE_SIZE;
1439 td_prnt[i + TABLE_SIZE] = i;
1442 while(j <= ROOT_POSITION) {
1443 td_freq[j] = td_freq[i] + td_freq[i + 1];
1445 td_prnt[i] = td_prnt[i + 1] = j;
1448 td_freq[TABLE_SIZE] = 0xffff;
1449 td_prnt[ROOT_POSITION] = 0;
1452 static void td_reconst()
1456 for(i = 0; i < TABLE_SIZE; i++) {
1457 if(td_son[i] >= TABLE_SIZE) {
1458 td_freq[j] = (td_freq[i] + 1) / 2;
1459 td_son[j] = td_son[i];
1463 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1465 f = td_freq[j] = td_freq[i] + td_freq[k];
1466 for(k = j - 1; f < td_freq[k]; k--);
1469 memmove(&td_freq[k + 1], &td_freq[k], l);
1471 memmove(&td_son[k + 1], &td_son[k], l);
1474 for(i = 0; i < TABLE_SIZE; i++) {
1475 if((k = td_son[i]) >= TABLE_SIZE) {
1478 td_prnt[k] = td_prnt[k + 1] = i;
1483 static void td_update(int c)
1486 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1489 c = td_prnt[c + TABLE_SIZE];
1492 if(k > td_freq[l = c + 1]) {
1493 while(k > td_freq[++l]);
1495 td_freq[c] = td_freq[l];
1499 if(i < TABLE_SIZE) {
1505 if(j < TABLE_SIZE) {
1512 while((c = td_prnt[c]) != 0);
1515 static short td_decode_char(FILEIO* fio)
1518 uint16_t c = td_son[ROOT_POSITION];
1519 while(c < TABLE_SIZE) {
1520 if((ret = td_get_bit(fio)) < 0) {
1531 static short td_decode_position(FILEIO* fio)
1535 if((bit = td_get_byte(fio)) < 0) {
1539 c = (uint16_t)td_d_code[i] << 6;
1540 j = td_d_len[i] - 2;
1542 if((bit = td_get_bit(fio)) < 0) {
1547 return (c | (i & 0x3f));
1550 static void td_init_decode()
1552 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1555 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1556 td_text_buf[i] = ' ';
1558 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1561 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1565 for(count = 0; count < len;) {
1566 if(td_bufcnt == 0) {
1567 if((c = td_decode_char(fio)) < 0) {
1571 *(buf++) = (uint8_t)c;
1572 td_text_buf[td_ptr++] = (uint8_t)c;
1573 td_ptr &= (STRING_BUFFER_SIZE - 1);
1576 if((pos = td_decode_position(fio)) < 0) {
1579 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1580 td_bufcnt = c - 255 + THRESHOLD;
1584 while(td_bufndx < td_bufcnt && count < len) {
1585 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1586 *(buf++) = (uint8_t)c;
1588 td_text_buf[td_ptr++] = (uint8_t)c;
1589 td_ptr &= (STRING_BUFFER_SIZE - 1);
1592 if(td_bufndx >= td_bufcnt) {
1593 td_bufndx = td_bufcnt = 0;
1620 uint8_t nsec, trk, head;
1629 bool DISK::teledisk_to_d88(FILEIO *fio)
1636 bool temporary = false;
1638 // check teledisk header
1639 fio->Fseek(0, FILEIO_SEEK_SET);
1640 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1641 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1642 // this image is compressed
1643 // decompress to the temporary file
1644 FILEIO* fio_tmp = new FILEIO();
1645 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1652 if((rd = td_decode(fio, obuf, 512)) > 0) {
1653 fio_tmp->Fwrite(obuf, rd, 1);
1661 // reopen the temporary file
1663 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1666 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1667 // this image is not compressed
1671 if(hdr.flag & 0x80) {
1673 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1674 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1677 // create d88 header
1681 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1682 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1683 d88_hdr.protect = 0; // non-protected
1686 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1689 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1690 fio->Fread(&trk, sizeof(td_trk_t), 1);
1691 while(trk.nsec != 0xff) {
1692 d88_hdr.trkptr[trkcnt++] = trkptr;
1693 if(hdr.sides == 1) {
1697 // read sectors in this track
1698 for(int i = 0; i < trk.nsec; i++) {
1699 uint8_t buf[2048], dst[2048];
1700 memset(buf, 0, sizeof(buf));
1701 memset(dst, 0, sizeof(dst));
1703 // read sector header
1704 fio->Fread(&sct, sizeof(td_sct_t), 1);
1706 // create d88 sector header
1707 memset(&d88_sct, 0, sizeof(d88_sct_t));
1712 d88_sct.nsec = trk.nsec;
1713 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1714 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1715 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1716 d88_sct.size = secsize[sct.n & 3];
1718 // create sector image
1719 if(sct.ctrl & 0x30) {
1720 d88_sct.stat = 0xf0; // data mark missing
1723 // read sector source
1724 int len = fio->Fgetc();
1725 len += fio->Fgetc() * 256 - 1;
1726 int flag = fio->Fgetc(), d = 0;
1727 fio->Fread(buf, len, 1);
1731 memcpy(dst, buf, len);
1732 } else if(flag == 1) {
1734 len2.read_2bytes_le_from(buf);
1739 } else if(flag == 2) {
1740 for(int s = 0; s < len;) {
1741 int type = buf[s++];
1742 int len2 = buf[s++];
1745 dst[d++] = buf[s++];
1747 } else if(type < 5) {
1753 for(int j = 0; j < n; j++) {
1757 for(int j = 0; j < n; j++) {
1762 break; // unknown type
1766 break; // unknown flag
1771 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1772 COPYBUFFER(dst, d88_sct.size);
1773 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1776 fio->Fread(&trk, sizeof(td_trk_t), 1);
1778 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1779 d88_hdr.size = trkptr;
1780 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1783 FILEIO::RemoveFile(_T("teledisk.$$$"));
1788 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1790 bool DISK::imagedisk_to_d88(FILEIO *fio)
1792 int size = fio->FileLength();
1793 fio->Fseek(0, FILEIO_SEEK_SET);
1794 fio->Fread(tmp_buffer, size, 1);
1796 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1801 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1808 // create d88 header
1812 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1813 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1814 d88_hdr.protect = 0; // non-protected
1817 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1820 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1825 // check track header
1826 uint8_t mode = tmp_buffer[pos++];
1827 uint8_t track = tmp_buffer[pos++];
1828 uint8_t head = tmp_buffer[pos++];
1829 uint8_t sector_count = tmp_buffer[pos++];
1830 uint8_t ssize = tmp_buffer[pos++];
1832 if(sector_count == 0) {
1838 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1841 const uint8_t *snum = &tmp_buffer[pos];
1842 pos += sector_count;
1843 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1845 pos += sector_count;
1846 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1848 pos += sector_count;
1852 int trkside = track * 2 + (head & 1);
1854 if(trkcnt < trkside) {
1857 d88_hdr.trkptr[trkside] = trkptr;
1859 if(img_mode == -1) {
1860 img_mode = mode & 3;
1863 // read sectors in this track
1864 for(int i = 0; i < sector_count; i++) {
1865 // create d88 sector header
1866 uint8_t stype = tmp_buffer[pos++];
1867 memset(&d88_sct, 0, sizeof(d88_sct_t));
1868 d88_sct.c = tnum ? tnum[i] : track;
1869 d88_sct.h = hnum ? hnum[i] : head;
1870 d88_sct.r = snum[i];
1872 d88_sct.nsec = sector_count;
1873 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1875 if(stype == 0 || stype > 8) {
1876 d88_sct.stat = 0xf0; // data mark missing
1879 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1880 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1881 d88_sct.size = actual_size;
1883 // create sector image
1884 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1885 memset(dst, tmp_buffer[pos++], actual_size);
1887 memcpy(dst, &tmp_buffer[pos], actual_size);
1888 pos += d88_sct.size;
1894 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1895 COPYBUFFER(dst, d88_sct.size);
1896 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1900 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1901 d88_hdr.size = trkptr;
1902 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1906 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1908 #define DSK_FORMAT_HEADER "MV - CPC"
1909 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1912 struct track_header {
1913 uint8_t headertag[13];
1916 uint8_t track_number;
1917 uint8_t side_number;
1920 uint8_t sector_size_code;
1921 uint8_t number_of_sector;
1922 uint8_t gap3_length;
1923 uint8_t filler_byte;
1925 struct sector_header {
1929 uint8_t sector_size_code;
1930 uint8_t fdc_status_reg1;
1931 uint8_t fdc_status_reg2;
1932 uint16_t data_length;
1936 bool DISK::cpdread_to_d88(FILEIO *fio)
1938 bool extendformat = false;
1939 int image_size = fio->FileLength();
1941 fio->Fseek(0, FILEIO_SEEK_SET);
1942 fio->Fread(tmp_buffer, image_size, 1);
1944 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1945 extendformat = true;
1946 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1947 extendformat = false;
1952 int heads = tmp_buffer[0x31];
1957 int tracks = tmp_buffer[0x30];
1958 int track_offsets[84 * 2];
1959 bool track_offsets_error = false;
1961 int cnt = 0, tmp = 0x100;
1962 for(int i = 0; i < tracks * heads; i++) {
1963 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1964 if(track_offsets_error) {
1967 track_offsets[cnt] = tmp;
1968 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1972 int cnt = 0, tmp = 0x100;
1973 for(int i = 0; i < tracks * heads; i++) {
1974 int length = tmp_buffer[0x34 + i] << 8;
1976 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1977 if(track_offsets_error) {
1980 track_offsets[cnt] = tmp;
1983 track_offsets[cnt] = image_size;
1988 if(track_offsets_error) {
1989 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1990 // so I modified this code to search "Track-Info" at the top of track information block
1991 int cnt = 0, tmp = 0x100;
1992 for(int i = 0; i < tracks * heads; i++) {
1994 for(; tmp < image_size; tmp += 0x10) {
1995 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
2001 track_offsets[cnt] = tmp;
2004 track_offsets[cnt] = image_size;
2010 // create d88 header
2014 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2015 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
2016 d88_hdr.protect = 0; // non-protected
2019 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2022 int total = 0, trkptr = sizeof(d88_hdr_t);
2024 for(int track = 0; track < tracks; track++) {
2025 for(int side = 0; side < heads; side++) {
2026 if(track_offsets[(track << 1) + side] >= image_size) {
2029 if((track << 1) + side < 164) {
2030 d88_hdr.trkptr[(track << 1) + side] = trkptr;
2034 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
2035 int pos = track_offsets[(track << 1) + side] + 0x100;
2036 for(int j = 0; j < tr.number_of_sector; j++) {
2037 sector_header sector;
2038 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2040 // create d88 sector header
2041 memset(&d88_sct, 0, sizeof(d88_sct_t));
2042 d88_sct.c = sector.track;
2043 d88_sct.h = sector.side;
2044 d88_sct.r = sector.sector_id;
2045 d88_sct.n = sector.sector_size_code;
2046 d88_sct.nsec = tr.number_of_sector;
2048 d88_sct.size = sector.data_length;
2049 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2051 d88_sct.size = 128 << tr.sector_size_code;
2052 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2054 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2055 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2058 if((track << 1) + side < 164) {
2059 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2060 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2061 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2063 total += d88_sct.size;
2066 pos += sector.data_length;
2068 pos += 128 << tr.sector_size_code;
2073 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2074 d88_hdr.size = trkptr;
2075 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2079 // solid image decoder
2081 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2087 solid_nside = nside;
2092 // create d88 header
2096 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2097 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2098 d88_hdr.protect = 0; // non-protected
2101 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2104 for(int i = 0; i < 8; i++) {
2105 if(size == (128 << i)) {
2112 int trkptr = sizeof(d88_hdr_t);
2114 for(int c = 0; c < ncyl; c++) {
2115 for(int h = 0; h < nside; h++) {
2116 d88_hdr.trkptr[t++] = trkptr;
2121 // read sectors in this track
2122 for(int s = 0; s < nsec; s++) {
2123 // create d88 sector header
2124 memset(&d88_sct, 0, sizeof(d88_sct_t));
2129 d88_sct.nsec = nsec;
2133 d88_sct.size = size;
2135 // create sector image
2137 memset(dst, 0xe5, sizeof(dst));
2138 fio->Fread(dst, size, 1);
2141 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2142 COPYBUFFER(dst, size);
2143 trkptr += sizeof(d88_sct_t) + size;
2147 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2148 d88_hdr.size = trkptr;
2149 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2153 #define STATE_VERSION 13
2155 void DISK::save_state(FILEIO* state_fio)
2157 state_fio->FputUint32(STATE_VERSION);
2159 state_fio->Fwrite(buffer, sizeof(buffer), 1);
2160 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2161 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2162 state_fio->FputUint32(file_size.d);
2163 state_fio->FputInt32(file_bank);
2164 state_fio->FputUint32(orig_file_size);
2165 state_fio->FputUint32(orig_crc32);
2166 state_fio->FputBool(trim_required);
2167 state_fio->FputBool(is_1dd_image);
2168 state_fio->FputBool(is_solid_image);
2169 state_fio->FputBool(is_fdi_image);
2170 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2171 state_fio->FputInt32(solid_ncyl);
2172 state_fio->FputInt32(solid_nside);
2173 state_fio->FputInt32(solid_nsec);
2174 state_fio->FputInt32(solid_size);
2175 state_fio->FputBool(solid_mfm);
2176 state_fio->FputBool(inserted);
2177 state_fio->FputBool(ejected);
2178 state_fio->FputBool(write_protected);
2179 state_fio->FputBool(changed);
2180 state_fio->FputUint8(media_type);
2181 state_fio->FputInt32(is_special_disk);
2182 state_fio->Fwrite(track, sizeof(track), 1);
2183 state_fio->FputInt32(sector_num.sd);
2184 state_fio->FputBool(track_mfm);
2185 state_fio->FputBool(invalid_format);
2186 // state_fio->FputBool(no_skew);
2187 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2188 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2189 state_fio->Fwrite(id_position, sizeof(id_position), 1);
2190 state_fio->Fwrite(data_position, sizeof(data_position), 1);
2191 // state_fio->FputInt32(gap3_size);
2192 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2193 state_fio->FputInt32(sector_size.sd);
2194 state_fio->Fwrite(id, sizeof(id), 1);
2195 state_fio->FputUint8(density);
2196 state_fio->FputBool(deleted);
2197 state_fio->FputBool(addr_crc_error);
2198 state_fio->FputBool(data_crc_error);
2199 state_fio->FputUint8(drive_type);
2200 state_fio->FputInt32(drive_rpm);
2201 state_fio->FputBool(drive_mfm);
2204 bool DISK::load_state(FILEIO* state_fio)
2206 if(state_fio->FgetUint32() != STATE_VERSION) {
2209 state_fio->Fread(buffer, sizeof(buffer), 1);
2210 state_fio->Fread(orig_path, sizeof(orig_path), 1);
2211 state_fio->Fread(dest_path, sizeof(dest_path), 1);
2212 file_size.d = state_fio->FgetUint32();
2213 file_bank = state_fio->FgetInt32();
2214 orig_file_size = state_fio->FgetUint32();
2215 orig_crc32 = state_fio->FgetUint32();
2216 trim_required = state_fio->FgetBool();
2217 is_1dd_image = state_fio->FgetBool();
2218 is_solid_image = state_fio->FgetBool();
2219 is_fdi_image = state_fio->FgetBool();
2220 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2221 solid_ncyl = state_fio->FgetInt32();
2222 solid_nside = state_fio->FgetInt32();
2223 solid_nsec = state_fio->FgetInt32();
2224 solid_size = state_fio->FgetInt32();
2225 solid_mfm = state_fio->FgetBool();
2226 inserted = state_fio->FgetBool();
2227 ejected = state_fio->FgetBool();
2228 write_protected = state_fio->FgetBool();
2229 changed = state_fio->FgetBool();
2230 media_type = state_fio->FgetUint8();
2231 is_special_disk = state_fio->FgetInt32();
2232 state_fio->Fread(track, sizeof(track), 1);
2233 sector_num.sd = state_fio->FgetInt32();
2234 track_mfm = state_fio->FgetBool();
2235 invalid_format = state_fio->FgetBool();
2236 // no_skew = state_fio->FgetBool();
2237 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2238 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2239 state_fio->Fread(id_position, sizeof(id_position), 1);
2240 state_fio->Fread(data_position, sizeof(data_position), 1);
2241 // gap3_size = state_fio->FgetInt32();
2242 int offset = state_fio->FgetInt32();
2243 sector = (offset != -1) ? buffer + offset : NULL;
2244 sector_size.sd = state_fio->FgetInt32();
2245 state_fio->Fread(id, sizeof(id), 1);
2246 density = state_fio->FgetUint8();
2247 deleted = state_fio->FgetBool();
2248 addr_crc_error = state_fio->FgetBool();
2249 data_crc_error = state_fio->FgetBool();
2250 drive_type = state_fio->FgetUint8();
2251 drive_rpm = state_fio->FgetInt32();
2252 drive_mfm = state_fio->FgetBool();