OSDN Git Service

[COMMON][VM][Qt] Add common wav-loading / saving helper functions to common.cpp .
[csp-qt/common_source_project-fm7.git] / source / src / vm / disk.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.09.16-
6
7         [ d88 handler ]
8 */
9
10 #ifndef _ANY2D88
11 #include "../emu.h"
12 #endif
13
14 #include "disk.h"
15 #include "../fileio.h"
16
17 #ifndef _ANY2D88
18 #define local_path(x) create_local_path(x)
19 #else
20 #define local_path(x) (x)
21 #endif
22 #define FM      false
23 #define MFM     true
24
25 // crc table
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
43 };
44
45 static const int secsize[8] = {
46         128, 256, 512, 1024, 2048, 4096, 8192, 16384
47 };
48
49 static uint8_t tmp_buffer[DISK_BUFFER_SIZE];
50
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
65 //#else
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
72 //#endif
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
84         { -1, 0, 0, 0, 0 },
85 };
86
87 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
88
89 void DISK::setup_fd_formats(void)
90 {
91         fd_format_t nt;
92         bool checked = false;
93         memset(fd_formats, 0, sizeof(fd_formats));
94 #if !defined(_ANY2D88)
95         osd = emu->get_osd();
96         if(osd->check_feature(_T("_SC3000"))) {
97                 checked = true;
98                 type_sc3000 = true;
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"))) {
101                 checked = true;
102                 type_smc70 = true;
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"))) {
105                 checked = true;
106                 type_x1 = true;
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"))) {
109                 checked = true;
110                 type_x1 = true;
111                 type_x1turbo = true;
112                 nt = { MEDIA_TYPE_2D,  40, 2, 16,  256, MFM };  // 2D   320KB
113         } else if(osd->check_feature(_T("_M5"))) {
114                 checked = true;
115                 type_m5 = true;
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"))) {
119                 checked = true;
120                 type_mz80b = true;
121                 nt = { MEDIA_TYPE_2DD, 80, 2, 16,  256, MFM };  // 2DD  640KB
122         } else if (osd->check_feature(_T("_YIS"))) {
123                 checked = true;
124                 type_yis = true;
125                 nt = { MEDIA_TYPE_2DD,  80, 1, 16,  256, MFM }; // 1DD  320KB
126         }
127         if(osd->check_feature(_T("_FM7")) || osd->check_feature(_T("_FM8"))) {
128                 checked = false;
129                 type_fm7 = true;
130         } else if(osd->check_feature(_T("_FM77_VARIANTS"))) {
131                 checked = false;
132                 type_fm7 = true;
133                 type_fm77 = true;
134         } else if(osd->check_feature(_T("_FM77AV_VARIANTS"))) {
135                 checked = false;
136                 type_fm7 = true;
137                 type_fm77 = true;
138                 type_fm77av = true;
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;
143                 }
144         }
145         if(osd->check_feature(_T("SUPPORT_MEDIA_TYPE_1DD"))) {
146                 type_1dd = true;
147         }
148         if(osd->check_feature(_T("_ANY2D88"))) {
149                 type_any2d88 = true;
150         }
151 #else // _ANY2D88
152         type_any2d88 = true;
153 #endif  
154         if(checked) {
155                 fd_formats[0] = nt;
156                 memcpy(&fd_formats[1], fd_formats_base, sizeof(fd_formats_base));
157         } else {
158                 memcpy(&fd_formats[0], fd_formats_base, sizeof(fd_formats_base));
159         }               
160 }
161
162 void DISK::open(const _TCHAR* file_path, int bank)
163 {
164         // check current disk image
165         if(inserted) {
166                 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
167                         return;
168                 }
169                 close();
170         }
171         if(bank < 0) {
172                 return;
173         }
174         memset(buffer, 0, sizeof(buffer));
175         file_bank = 0;
176         write_protected = false;
177         media_type = MEDIA_TYPE_UNK;
178         is_special_disk = 0;
179         is_solid_image = is_fdi_image = is_1dd_image = false;
180         trim_required = false;
181         track_mfm = drive_mfm;
182         
183         // open disk image
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);
188                 
189                 file_size.d = fio->FileLength();
190                 fio->Fseek(0, FILEIO_SEEK_SET);
191                 
192                 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
193                         // d88 image
194                         uint32_t offset = 0;
195                         for(int i = 0; i < bank; i++) {
196                                 fio->Fseek(offset + 0x1c, SEEK_SET);
197                                 offset += fio->FgetUint32_LE();
198                         }
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);
203                         file_bank = bank;
204                         if(check_file_extension(file_path, _T(".1dd"))) {
205                                 is_1dd_image = true;
206                                 media_type = MEDIA_TYPE_2DD;
207                         }
208                         inserted = changed = true;
209 //                      trim_required = true;
210                         
211                         // fix sector number from big endian to little endian
212                         for(int trkside = 0; trkside < 164; trkside++) {
213                                 pair_t offset;
214                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
215                                 
216                                 if(!IS_VALID_TRACK(offset.d)) {
217                                         break;
218                                 }
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);
223                                 if(is_be) {
224                                         sector_num.read_2bytes_be_from(t + 4);
225                                         sector_num.write_2bytes_le_to(t + 4);
226                                 }
227                                 for(int i = 0; i < sector_num.sd; i++) {
228                                         if(is_be) {
229                                                 sector_num.write_2bytes_le_to(t + 4);
230                                         }
231                                         data_size.read_2bytes_le_from(t + 14);
232                                         t += data_size.sd + 0x10;
233                                 }
234                         }
235                 } else if(check_file_extension(file_path, _T(".td0"))) {
236                         // teledisk image
237                         try {
238                                 if(teledisk_to_d88(fio)) {
239                                         inserted = changed = true;
240                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
241                                 }
242                         } catch(...) {
243                                 // failed to convert the disk image
244                         }
245                 } else if(check_file_extension(file_path, _T(".imd"))) {
246                         // imagedisk image
247                         try {
248                                 if(imagedisk_to_d88(fio)) {
249                                         inserted = changed = true;
250                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
251                                 }
252                         } catch(...) {
253                                 // failed to convert the disk image
254                         }
255                 } else if(check_file_extension(file_path, _T(".dsk"))) {
256                         // cpdread image
257                         try {
258                                 if(cpdread_to_d88(fio)) {
259                                         inserted = changed = true;
260                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
261                                 }
262                         } catch(...) {
263                                 // failed to convert the disk image
264                         }
265                 } else if(check_file_extension(file_path, _T(".nfd"))) {
266                         // T98-NEXT nfd r0/r1 image for NEC PC-98x1 series
267                         try {
268                                 if(nfdr0_to_d88(fio) || nfdr1_to_d88(fio)) {
269                                         inserted = changed = true;
270                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
271                                 }
272                         } catch(...) {
273                                 // failed to convert the disk image
274                         }
275                 } else if(check_file_extension(file_path, _T(".fdi"))) {
276                         // Anex86 fdi image for NEC PC-98x1 series
277                         if(file_size.d == 4096 + 77 * 2 * 8 * 1024) {
278                                 try {
279                                         fio->Fread(fdi_header, 4096, 1);
280                                         if(solid_to_d88(fio, MEDIA_TYPE_2HD, 77, 2, 8, 1024, true)) {
281                                                 inserted = changed = is_solid_image = is_fdi_image = true;
282                                         }
283                                 } catch(...) {
284                                         // failed to convert the disk image
285                                 }
286                         } else if(file_size.d == 4096 + 80 * 2 * 15 * 512) {
287                                 try {
288                                         fio->Fread(fdi_header, 4096, 1);
289                                         if(solid_to_d88(fio, MEDIA_TYPE_2HD, 80, 2, 15, 512, true)) {
290                                                 inserted = changed = is_solid_image = is_fdi_image = true;
291                                         }
292                                 } catch(...) {
293                                         // failed to convert the disk image
294                                 }
295                         } else if(file_size.d == 4096 + 80 * 2 * 18 * 512) {
296                                 try {
297                                         fio->Fread(fdi_header, 4096, 1);
298                                         if(solid_to_d88(fio, MEDIA_TYPE_144, 80, 2, 18, 512, true)) {
299                                                 inserted = changed = is_solid_image = is_fdi_image = true;
300                                         }
301                                 } catch(...) {
302                                         // failed to convert the disk image
303                                 }
304                         } else if(file_size.d == 4096 + 77 * 2 * 26 * 256) {
305                                 try {
306                                         fio->Fread(fdi_header, 4096, 1);
307                                         if(solid_to_d88(fio, MEDIA_TYPE_2HD, 77, 2, 26, 256, true)) {
308                                                 inserted = changed = is_solid_image = is_fdi_image = true;
309                                         }
310                                 } catch(...) {
311                                         // failed to convert the disk image
312                                 }
313                         } else if(file_size.d == 4096 + 80 * 2 * 9 * 512) {
314                                 try {
315                                         fio->Fread(fdi_header, 4096, 1);
316                                         if(solid_to_d88(fio, MEDIA_TYPE_2DD, 80, 2, 9, 512, true)) {
317                                                 inserted = changed = is_solid_image = is_fdi_image = true;
318                                         }
319                                 } catch(...) {
320                                         // failed to convert the disk image
321                                 }
322                         } else if(file_size.d == 4096 + 80 * 2 * 8 * 512) {
323                                 try {
324                                         fio->Fread(fdi_header, 4096, 1);
325                                         if(solid_to_d88(fio, MEDIA_TYPE_2DD, 80, 2, 8, 512, true)) {
326                                                 inserted = changed = is_solid_image = is_fdi_image = true;
327                                         }
328                                 } catch(...) {
329                                         // failed to convert the disk image
330                                 }
331                         }
332                 } else if(check_file_extension(file_path, _T(".hdm")) && file_size.d == 77 * 2 * 8 * 1024) {
333                         // BKDSK hdm image for NEC PC-98x1 series
334                         try {
335                                 if(solid_to_d88(fio, MEDIA_TYPE_2HD, 77, 2, 8, 1024, true)) {
336                                         inserted = changed = is_solid_image = true;
337                                 }
338                         } catch(...) {
339                                 // failed to convert the disk image
340                         }
341                 } else if(check_file_extension(file_path, _T(".hd5")) && file_size.d == 80 * 2 * 15 * 512) {
342                         // BKDSK hd5 image for NEC PC-98x1 series
343                         try {
344                                 if(solid_to_d88(fio, MEDIA_TYPE_2HD, 80, 2, 15, 512, true)) {
345                                         inserted = changed = is_solid_image = true;
346                                 }
347                         } catch(...) {
348                                 // failed to convert the disk image
349                         }
350                 } else if(check_file_extension(file_path, _T(".hd4")) && file_size.d == 80 * 2 * 18 * 512) {
351                         // BKDSK hd4 image for NEC PC-98x1 series
352                         try {
353                                 if(solid_to_d88(fio, MEDIA_TYPE_144, 80, 2, 18, 512, true)) {
354                                         inserted = changed = is_solid_image = true;
355                                 }
356                         } catch(...) {
357                                 // failed to convert the disk image
358                         }
359                 } else if(check_file_extension(file_path, _T(".hdb")) && file_size.d == 77 * 2 * 26 * 256) {
360                         // BKDSK hdb image for NEC PC-98x1 series
361                         try {
362                                 if(solid_to_d88(fio, MEDIA_TYPE_2HD, 77, 2, 26, 256, true)) {
363                                         inserted = changed = is_solid_image = true;
364                                 }
365                         } catch(...) {
366                                 // failed to convert the disk image
367                         }
368                 } else if(check_file_extension(file_path, _T(".dd9")) && file_size.d == 80 * 2 * 9 * 512) {
369                         // BKDSK dd9 image for NEC PC-98x1 series
370                         try {
371                                 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 80, 2, 9, 512, true)) {
372                                         inserted = changed = is_solid_image = true;
373                                 }
374                         } catch(...) {
375                                 // failed to convert the disk image
376                         }
377                 } else if(check_file_extension(file_path, _T(".dd6")) && file_size.d == 80 * 2 * 8 * 512) {
378                         // BKDSK dd6 image for NEC PC-98x1 series
379                         try {
380                                 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 80, 2, 8, 512, true)) {
381                                         inserted = changed = is_solid_image = true;
382                                 }
383                         } catch(...) {
384                                 // failed to convert the disk image
385                         }
386                 } else if(check_file_extension(file_path, _T(".xdf")) && file_size.d == 77 * 2 * 8 * 1024) {
387                         // EX68 xdf image for SHARP X680x0 series
388                         try {
389                                 if(solid_to_d88(fio, MEDIA_TYPE_2HD, 77, 2, 8, 1024, true)) {
390                                         inserted = changed = is_solid_image = true;
391                                 }
392                         } catch(...) {
393                                 // failed to convert the disk image
394                         }
395                 } else if(check_file_extension(file_path, _T(".2d"))  && file_size.d == 40 * 2 * 16 * 256) {
396                         // 2d image for SHARP X1 series
397                         try {
398                                 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true)) {
399                                         inserted = changed = is_solid_image = true;
400                                 }
401                         } catch(...) {
402                                 // failed to convert the disk image
403                         }
404                 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
405                         // sf7 image for SEGA SC-3000 + SF-7000
406                         try {
407                                 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true)) {
408                                         inserted = changed = is_solid_image = true;
409                                 }
410                         } catch(...) {
411                                 // failed to convert the disk image
412                         }
413                 } else if(check_file_extension(file_path, _T(".img"))  && file_size.d == 70 * 1 * 16 * 256) {
414                         // img image for SONY SMC-70/777 series
415                         try {
416                                 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true)) {
417                                         inserted = changed = is_solid_image = true;
418                                 }
419                         } catch(...) {
420                                 // failed to convert the disk image
421                         }
422                 }
423                 if(!inserted) {
424                         // check solid image file format
425                         for(int i = 0;; i++) {
426                                 const fd_format_t *p = &fd_formats[i];
427                                 if(p->type == -1) {
428                                         break;
429                                 }
430                                 if(file_size.d == (uint32_t)(p->ncyl * p->nside * p->nsec * p->size)) {
431                                         fio->Fseek(0, FILEIO_SEEK_SET);
432                                         int type = p->type;
433                                         int ncyl = p->ncyl;
434                                         int nside = p->nside;
435                                         int nsec = p->nsec;
436                                         int size = p->size;
437 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
438                                                 if(type_1dd) {
439                                                         if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
440                                                                 type = MEDIA_TYPE_2DD;
441                                                                 nside = 1;
442                                                                 ncyl *= 2;
443                                                         }
444                                                 } else if(type_any2d88) {
445 //#elif defined(_ANY2D88)
446                                                         if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
447                                                                 type = MEDIA_TYPE_2DD;
448                                                                 nside = 1;
449                                                                 ncyl *= 2;
450                                                         }
451                                                         if(open_as_256 && (size == 512 || size == 1024)) {
452                                                                 nsec *= size / 256;
453                                                                 size = 256;
454                                                         }
455                                                 }
456 //#endif
457                                         try {
458 //                                              if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
459                                                 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
460                                                         inserted = changed = is_solid_image = true;
461                                                 }
462                                         } catch(...) {
463                                                 // failed to convert the disk image
464                                         }
465                                         if(inserted) {
466                                                 break;
467                                         }
468                                 }
469                         }
470                 }
471                 if(fio->IsOpened()) {
472                         fio->Fclose();
473                 }
474         }
475         delete fio;
476         
477         // check loaded image
478         if(inserted) {
479                 // check media type
480                 if(media_type == MEDIA_TYPE_UNK) {
481                         if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
482                                 // check 1.2MB or 1.44MB
483                                 for(int trkside = 0; trkside < 164; trkside++) {
484                                         pair_t offset;
485                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
486                                         
487                                         if(!IS_VALID_TRACK(offset.d)) {
488                                                 continue;
489                                         }
490                                         // track found
491                                         uint8_t *t = buffer + offset.d;
492                                         pair_t sector_num, data_size;
493                                         sector_num.read_2bytes_le_from(t + 4);
494                                         data_size.read_2bytes_le_from(t + 14);
495                                         
496                                         if(sector_num.sd >= 18 && data_size.sd == 512) {
497                                                 media_type = MEDIA_TYPE_144;
498                                         }
499                                         break;
500                                 }
501                         }
502                 }
503                 
504                 // check two side
505                 int valid_side = 0;
506                 
507                 for(int trk = 0; trk < 82; trk++) {
508                         for(int side = 0; side < 2; side++) {
509                                 int trkside = trk * 2 + side;
510                                 pair_t offset;
511                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
512                                 
513                                 if(IS_VALID_TRACK(offset.d)) {
514                                         valid_side |= (1 << side);
515                                 }
516                         }
517                         if(valid_side == 3) break;
518                 }
519                 // FIXME: unformat disk is recognized as two side
520                 two_side = (valid_side != 1);
521                 
522                 // fix write protect flag
523                 if(buffer[0x1a] != 0) {
524                         buffer[0x1a] = 0x10;
525                         write_protected = true;
526                 }
527                 
528                 // get crc32 for midification check
529                 orig_file_size = file_size.d;
530                 orig_crc32 = get_crc32(buffer, file_size.d);
531                 
532                 // check special disk image
533 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
534                 if(type_fm7) {
535                         // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
536                         if(media_type == MEDIA_TYPE_2D) {
537                                 // check first track
538                                 pair_t offset, sector_num, data_size;
539                                 offset.read_4bytes_le_from(buffer + 0x20);
540
541                                 if(IS_VALID_TRACK(offset.d)) {
542                                         // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
543                                         uint8_t* t = buffer + offset.d;
544                                         sector_num.read_2bytes_le_from(t + 4);
545                                         for(int _i = 0; _i < sector_num.sd; _i++) {
546                                                 data_size.read_2bytes_le_from(t + 14);
547                                                 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
548                                                         /* Type 1: Sec07, +$50- "1989/09/12 ... "*/
549                                                         static const uint8_t gamblerfm_1[] = {
550                                                                 0x31, 0x39, 0x38, 0x39, 0x2f, 0x30, 0x39, 0x2f,
551                                                                 0x31, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552                                                                 0x28, 0x43, 0x29, 0x47, 0x41, 0x4d, 0x45, 0x41,
553                                                                 0x52, 0x54, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
554                                                                 0x20, 0x20, 0x20, 0x59, 0x45, 0x4c, 0x4c, 0x4f,
555                                                                 0x57, 0x48, 0x4f, 0x52, 0x4e, 0x00, 0x00, 0x00,
556                                                                 0x20, 0x20, 0x20, 0x4b, 0x4f, 0x55, 0x44, 0x41,
557                                                                 0x4e, 0x53, 0x59, 0x41, 0x20, 0x59, 0x4f, 0x55,
558                                                                 0x4e, 0x47, 0x2d, 0x4d, 0x41, 0x47, 0x41, 0x5a,
559                                                                 0x49, 0x4e, 0x45, 0x00 
560                                                         };
561                                                         /* Type 2: Sec07, +$30- */
562                                                         static const uint8_t gamblerfm_2[] = {
563                                                                 0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7,
564                                                                 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3,
565                                                                 0xbc, 0xdd, 0xca
566                                                         };
567                                                         if(memcmp((void *)(t + 0x50), gamblerfm_1, sizeof(gamblerfm_1)) == 0) {
568                                                                 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
569                                                                 break;
570                                                         }
571                                                         if(memcmp((void *)(t + 0x30), gamblerfm_2, sizeof(gamblerfm_2)) == 0) {
572                                                                 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
573                                                                 break;
574                                                         }
575                                                 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
576                                                         //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
577                                                         static const uint8_t deathforce[] ={
578                                                                 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
579                                                                 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
580                                                                 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
581                                                                 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
582                                                                 0x00, 0x00
583                                                         };
584                                                         if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
585                                                                 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
586                                                                 break;
587                                                         }
588                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 5 && t[3] == 1) {
589                                                         //$00 * 16 + $00 + "Protected by  N & A (SUPER HACKER COMBI)
590                                                         //Can you found CHECK-ROUTINES ?Can you crack these protect ?
591                                                         //good bye !ou "
592                                                         static const uint8_t xanadu2fm_d_1[] ={
593                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595                                                         };
596                                                         static const uint8_t xanadu2fm_d_2[] = {
597                                                                 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
598                                                                 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
599                                                                 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
600                                                                 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
601                                                                 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
602                                                                 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
603                                                                 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
604                                                                 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
605                                                                 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
606                                                                 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
607                                                                 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
608                                                                 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
609                                                                 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
610                                                                 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
611                                                         };
612                                                         if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
613                                                                 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
614                                                                         is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
615                                                                         break;
616                                                                 }
617                                                         }
618                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 8 && t[3] == 1) {
619                                                         // Xanadu 1
620                                                         static const uint8_t xanadu1fm_d_1[] = {
621                                                                 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
622                                                                 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
623                                                                 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
624                                                                 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
625                                                                 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
626                                                                 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
627                                                                 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
628                                                                 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
629                                                                 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
630                                                                 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
631                                                                 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
632                                                         };
633                                                         static const uint8_t xanadu1fm_d_2[] = {
634                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636                                                                 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
637                                                                 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
638                                                                 0x90, 0x8E, 
639                                                         };
640                                                         if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
641                                                                 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
642                                                                         is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
643                                                                         break;
644                                                                 }
645                                                         }
646                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
647                                                         //$03 + $2D + "PSY-O-BLADE   Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
648                                                         static const uint8_t psyoblade_ipl1[] ={
649                                                                 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
650                                                                 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
651                                                                 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
652                                                                 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
653                                                                 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
654                                                                 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
655                                                                 0xfd, 0x05
656                                                         };
657                                                         //IPL Signature1
658                                                         static const uint8_t psyoblade_disk_1[] ={
659                                                                 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
660                                                                 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
661                                                                 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
662                                                                 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
663                                                         };
664                                                         //$00 + $00 + $03 + $14 + "PSY-O-BLADE  DISK" + $B6 + $FD + $05
665                                                         static const uint8_t psyoblade_disk_2[] ={
666                                                                 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
667                                                                 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
668                                                                 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
669                                                         };
670                                                         //RIGLAS/FM: $3E - $7D 
671                                                         static const uint8_t riglas_fm[] = {
672                                                                 0x0d, 0x56, /* $3e-$3f */
673                                                                 0x44, 0x53, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, /* $40-$47 */
674                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1b, 0x02, /* $48-$4f */
675                                                                 0x1e, 0x00, 0x04, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $50-$57 */
676                                                                 0x43, 0x4f, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00, /* $58-$5f */
677                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1f, 0x03, /* $60-$67 */
678                                                                 0x03, 0x00, 0x05, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $68-$6f */
679                                                                 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x00, 0x00, /* $70-$77 */
680                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x03              /* $78-$7d */
681                                                         };
682                                                         if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
683                                                                 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
684                                                                 break;
685                                                         } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
686                                                                 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
687                                                                         is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
688                                                                         break;
689                                                                 }
690                                                         } else if(memcmp((void *)(t + 0x3e + 0x10), riglas_fm, sizeof(riglas_fm)) == 0) {
691                                                                 is_special_disk = SPECIAL_DISK_FM7_RIGLAS;
692                                                                 break;
693                                                         }
694                                         } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
695                                                         static const uint8_t taiyoufm1[] = {
696                                                                 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
697                                                                 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
698                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
699                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
700                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
701                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
702                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
703                                                                 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
704                                                                 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
705                                                                 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
706                                                         };
707                                                         if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
708                                                                 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
709                                                                 break;
710                                                         }
711                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
712                                                         static const uint8_t taiyoufm2[] = {
713                                                                 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
714                                                                 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
715                                                                 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
716                                                                 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
717                                                                 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
718                                                                 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
719                                                                 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
720                                                                 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
721                                                         };
722                                                         if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
723                                                                 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
724                                                                 break;
725                                                         }
726                                                 }
727                                                 t += data_size.sd + 0x10;
728                                         }
729                                 }
730                         }
731                 } else if(type_x1) { 
732 //#elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
733                         // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
734                         if(media_type == MEDIA_TYPE_2D) {
735                                 // check first track
736                                 pair_t offset;
737                                 offset.read_4bytes_le_from(buffer + 0x20);
738                                 if(IS_VALID_TRACK(offset.d)) {
739                                         // check first sector
740                                         static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
741                                         uint8_t *t = buffer + offset.d;
742 //#if defined(_X1TURBO) || defined(_X1TURBOZ)
743 //                              if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
744 //                                      is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
745 //                              } else
746 //#endif
747                                                 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
748                                                         is_special_disk = SPECIAL_DISK_X1_BATTEN;
749                                                 }
750                                 }
751                         }
752                 }
753 //#endif
754         }
755 }
756
757 void DISK::close()
758 {
759         // write disk image
760         if(inserted) {
761                 if(trim_required) {
762                         trim_buffer();
763                         trim_required = false;
764                 }
765                 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
766                 
767                 if(/*!write_protected &&*/ !(file_size.d == orig_file_size && get_crc32(buffer, file_size.d) == orig_crc32)) {
768                         // write image
769                         FILEIO* fio = new FILEIO();
770                         int pre_size = 0, post_size = 0;
771                         uint8_t *pre_buffer = NULL, *post_buffer = NULL;
772                         
773                         // is this d88 format ?
774                         if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
775                                 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
776                                         fio->Fseek(0, FILEIO_SEEK_END);
777                                         uint32_t total_size = fio->Ftell(), offset = 0;
778                                         for(int i = 0; i < file_bank; i++) {
779                                                 fio->Fseek(offset + 0x1c, SEEK_SET);
780                                                 offset += fio->FgetUint32_LE();
781                                         }
782                                         if((pre_size = offset) > 0) {
783                                                 pre_buffer = (uint8_t *)malloc(pre_size);
784                                                 fio->Fseek(0, FILEIO_SEEK_SET);
785                                                 fio->Fread(pre_buffer, pre_size, 1);
786                                         }
787                                         fio->Fseek(offset + 0x1c, SEEK_SET);
788                                         offset += fio->FgetUint32_LE();
789                                         if((post_size = total_size - offset) > 0) {
790                                                 post_buffer = (uint8_t *)malloc(post_size);
791                                                 fio->Fseek(offset, FILEIO_SEEK_SET);
792                                                 fio->Fread(post_buffer, post_size, 1);
793                                         }
794                                         fio->Fclose();
795                                 }
796                         }
797                         
798                         // is this solid image and was physical formatted ?
799                         if(is_solid_image) {
800                                 bool formatted = false;
801                                 int tracks = 0;
802                                 
803                                 for(int trkside = 0; trkside < 164; trkside++) {
804                                         pair_t offset;
805                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
806                                         
807                                         if(!IS_VALID_TRACK(offset.d)) {
808                                                 continue;
809                                         }
810                                         if(solid_nside == 1 && (trkside & 1) == 1) {
811                                                 formatted = true;
812                                         }
813                                         tracks++;
814                                         
815                                         uint8_t* t = buffer + offset.d;
816                                         pair_t sector_num, data_size;
817                                         sector_num.read_2bytes_le_from(t + 4);
818                                         
819                                         if(sector_num.sd != solid_nsec) {
820                                                 formatted = true;
821                                         }
822                                         for(int i = 0; i < sector_num.sd; i++) {
823                                                 data_size.read_2bytes_le_from(t + 14);
824                                                 if(data_size.sd != solid_size) {
825                                                         formatted = true;
826                                                 }
827                                                 if(t[6] != (solid_mfm ? 0 : 0x40)) {
828                                                         formatted = true;
829                                                 }
830                                                 t += data_size.sd + 0x10;
831                                         }
832                                 }
833                                 if(tracks != (solid_ncyl * solid_nside)) {
834                                         formatted = true;
835                                 }
836                                 if(formatted) {
837                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
838                                         is_solid_image = false;
839                                 }
840                         }
841                         
842                         if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
843                                 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
844                         }
845                         if(fio->IsOpened()) {
846                                 if(pre_buffer) {
847                                         fio->Fwrite(pre_buffer, pre_size, 1);
848                                 }
849                                 if(is_solid_image) {
850                                         if(is_fdi_image) {
851                                                 fio->Fwrite(fdi_header, 4096, 1);
852                                         }
853                                         for(int trkside = 0; trkside < 164; trkside++) {
854                                                 pair_t offset;
855                                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
856                                                 
857                                                 if(!IS_VALID_TRACK(offset.d)) {
858                                                         continue;
859                                                 }
860                                                 uint8_t* t = buffer + offset.d;
861                                                 pair_t sector_num, data_size;
862                                                 sector_num.read_2bytes_le_from(t + 4);
863                                                 
864                                                 for(int i = 0; i < sector_num.sd; i++) {
865                                                         data_size.read_2bytes_le_from(t + 14);
866                                                         fio->Fwrite(t + 0x10, data_size.sd, 1);
867                                                         t += data_size.sd + 0x10;
868                                                 }
869                                         }
870                                 } else {
871                                         fio->Fwrite(buffer, file_size.d, 1);
872                                 }
873                                 if(post_buffer) {
874                                         fio->Fwrite(post_buffer, post_size, 1);
875                                 }
876                                 fio->Fclose();
877                         }
878                         if(pre_buffer) {
879                                 free(pre_buffer);
880                         }
881                         if(post_buffer) {
882                                 free(post_buffer);
883                         }
884                         delete fio;
885                 }
886                 ejected = true;
887         }
888         inserted = write_protected = false;
889         file_size.d = 0;
890         sector_size.sd = sector_num.sd = 0;
891         sector = NULL;
892 }
893
894 //#ifdef _ANY2D88
895 void DISK::save_as_d88(const _TCHAR* file_path)
896 {
897 //#ifdef _ANY2D88
898         if(inserted) {
899                 FILEIO* fio = new FILEIO();
900                 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
901                         if(is_1dd_image) {
902                                 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
903                                 for(int trk = 0; trk < 82; trk++) {
904                                         memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
905                                         memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
906                                 }
907                                 buffer[0x1b] = MEDIA_TYPE_2DD;
908                         }
909                         fio->Fwrite(buffer, file_size.d, 1);
910                         fio->Fclose();
911                 }
912                 delete fio;
913         }
914 //#endif
915 }
916 //#endif
917
918 bool DISK::get_track(int trk, int side)
919 {
920         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
921                 if(trk >= 0) trk >>= 1;
922         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
923                 if(trk >= 0) trk <<= 1;
924         }
925         return get_track_tmp(trk, side);
926 }
927
928 bool DISK::get_track_tmp(int trk, int side)
929 {
930         sector_size.sd = sector_num.sd = 0;
931         invalid_format = false;
932 //      no_skew = true;
933         
934         // disk not inserted or invalid media type
935         if(!(inserted && check_media_type())) {
936                 return false;
937         }
938         
939         // search track
940         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
941         if(!(0 <= trkside && trkside < 164)) {
942                 return false;
943         }
944         cur_track = trk;
945         cur_side = side;
946         
947         pair_t offset;
948         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
949         
950         if(!IS_VALID_TRACK(offset.d)) {
951                 return false;
952         }
953         
954         // track found
955         sector = buffer + offset.d;
956         sector_num.read_2bytes_le_from(sector + 4);
957         pair_t data_size;
958         data_size.read_2bytes_le_from(sector + 14);
959         
960         // create each sector position in track
961         track_mfm = false;
962         if(sector_num.sd == 0) {
963                 track_mfm = drive_mfm;
964         } else {
965                 uint8_t* t = sector;
966                 for(int i = 0; i < sector_num.sd; i++) {
967                         data_size.read_2bytes_le_from(t + 14);
968                         // t[6]: 0x00 = double-density, 0x40 = single-density
969                         if(t[6] == 0x00) {
970                                 track_mfm = true;
971                                 break;
972                         }
973                         t += data_size.sd + 0x10;
974                 }
975         }
976         int sync_size  = track_mfm ? 12 : 6;
977         int am_size = track_mfm ? 3 : 0;
978         int gap0_size = track_mfm ? 80 : 40;
979         int gap1_size = track_mfm ? 50 : 26;
980         int gap2_size = track_mfm ? 22 : 11;
981         int gap3_size = 0, gap4_size;
982         
983         if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
984                 if(track_mfm) {
985                         if(data_size.sd ==  256 && sector_num.sd == 26) gap3_size =  54;
986                         if(data_size.sd ==  512 && sector_num.sd == 15) gap3_size =  84;
987                         if(data_size.sd == 1024 && sector_num.sd ==  8) gap3_size = 116;
988                 } else {
989                         if(data_size.sd ==  128 && sector_num.sd == 26) gap3_size =  27;
990                         if(data_size.sd ==  256 && sector_num.sd == 15) gap3_size =  42;
991                         if(data_size.sd ==  512 && sector_num.sd ==  8) gap3_size =  58;
992                 }
993         } else {
994                 if(track_mfm) {
995                         if(data_size.sd ==  256 && sector_num.sd == 16) gap3_size =  51;
996                         if(data_size.sd ==  512 && sector_num.sd ==  9) gap3_size =  80;
997                         if(data_size.sd == 1024 && sector_num.sd ==  5) gap3_size = 116;
998                 } else {
999                         if(data_size.sd ==  128 && sector_num.sd == 16) gap3_size =  27;
1000                         if(data_size.sd ==  256 && sector_num.sd ==  9) gap3_size =  42;
1001                         if(data_size.sd ==  512 && sector_num.sd ==  5) gap3_size =  58;
1002                 }
1003         }
1004         
1005         uint8_t* t = sector;
1006         int total = 0, valid_sector_num = 0;
1007         
1008         for(int i = 0; i < sector_num.sd; i++) {
1009                 data_size.read_2bytes_le_from(t + 14);
1010                 sync_position[i] = total; // for invalid format case
1011                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
1012                 if(data_size.sd > 0) {
1013                         total += sync_size + (am_size + 1);
1014                         total += data_size.sd + 2;
1015                         valid_sector_num++;
1016                 }
1017 //              if(t[2] != i + 1) {
1018 //                      no_skew = false;
1019 //              }
1020                 t += data_size.sd + 0x10;
1021         }
1022         total += sync_size + (am_size + 1); // sync in preamble
1023         
1024         if(gap3_size == 0) {
1025                 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
1026         }
1027         gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
1028         
1029         if(gap3_size < 8 || gap4_size < 8) {
1030                 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
1031                 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
1032         }
1033         if(gap3_size < 8 || gap4_size < 8) {
1034                 gap0_size = gap1_size = gap3_size = gap4_size = 8;
1035                 invalid_format = true;
1036         }
1037         int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
1038         
1039         if(invalid_format) {
1040                 total -= sync_size + (am_size + 1);
1041                 for(int i = 0; i < sector_num.sd; i++) {
1042                         sync_position[i] *= get_track_size() - preamble_size - gap4_size;
1043                         sync_position[i] /= total;
1044                 }
1045         }
1046         t = sector;
1047         total = preamble_size;
1048         sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
1049         
1050         for(int i = 0; i < sector_num.sd; i++) {
1051                 data_size.read_2bytes_le_from(t + 14);
1052                 if(invalid_format) {
1053                         total = preamble_size + sync_position[i];
1054                 }
1055                 sync_position[i] = total;
1056                 total += sync_size;
1057                 am1_position[i] = total;
1058                 total += am_size + 1;
1059                 id_position[i] = total;
1060                 total += (4 + 2) + gap2_size;
1061                 if(data_size.sd > 0) {
1062                         total += sync_size + (am_size + 1);
1063                         data_position[i] = total;
1064                         total += data_size.sd + 2;
1065                         total += gap3_size;
1066                 } else {
1067                         data_position[i] = total; // FIXME
1068                 }
1069                 t += data_size.sd + 0x10;
1070         }
1071         return true;
1072 }
1073
1074 bool DISK::make_track(int trk, int side)
1075 {
1076         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1077                 if(trk >= 0) trk >>= 1;
1078         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1079                 if(trk >= 0) trk <<= 1;
1080         }
1081         return make_track_tmp(trk, side);
1082 }
1083
1084 bool DISK::make_track_tmp(int trk, int side)
1085 {
1086         int track_size = get_track_size();
1087         
1088         if(!get_track_tmp(trk, side)) {
1089                 // create a dummy track
1090                 for(int i = 0; i < track_size; i++) {
1091                         track[i] = rand();
1092                 }
1093                 return false;
1094         }
1095         
1096         // make track image
1097         int sync_size  = track_mfm ? 12 : 6;
1098         int am_size = track_mfm ? 3 : 0;
1099         int gap2_size = track_mfm ? 22 : 11;
1100         uint8_t gap_data = track_mfm ? 0x4e : 0xff;
1101         
1102         // preamble
1103         memset(track, gap_data, track_size);
1104         int q = sync_position[array_length(sync_position) - 1];
1105         
1106         // sync
1107         for(int i = 0; i < sync_size; i++) {
1108                 track[q++] = 0x00;
1109         }
1110         // index mark
1111         for(int i = 0; i < am_size; i++) {
1112                 track[q++] = 0xc2;
1113         }
1114         track[q++] = 0xfc;
1115         
1116         // sectors
1117         uint8_t *t = sector;
1118         
1119         for(int i = 0; i < sector_num.sd; i++) {
1120                 pair_t data_size;
1121                 data_size.read_2bytes_le_from(t + 14);
1122                 int p = sync_position[i];
1123                 
1124                 // sync
1125                 for(int j = 0; j < sync_size; j++) {
1126                         if(p < track_size) track[p++] = 0x00;
1127                 }
1128                 // am1
1129                 uint16_t crc = 0xffff;
1130                 for(int j = 0; j < am_size; j++) {
1131                         if(p < track_size) track[p++] = 0xa1;
1132                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1133                 }
1134                 if(p < track_size) track[p++] = 0xfe;
1135                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1136                 // id
1137                 if(p < track_size) track[p++] = t[0];
1138                 if(p < track_size) track[p++] = t[1];
1139                 if(p < track_size) track[p++] = t[2];
1140                 if(p < track_size) track[p++] = t[3];
1141                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1142                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1143                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1144                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1145                 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1146                 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1147                 // gap2
1148                 for(int j = 0; j < gap2_size; j++) {
1149                         if(p < track_size) track[p++] = gap_data;
1150                 }
1151                 // data field
1152                 if(data_size.sd > 0) {
1153                         // sync
1154                         for(int j = 0; j < sync_size; j++) {
1155                                 if(p < track_size) track[p++] = 0x00;
1156                         }
1157                         // am2
1158                         crc = 0xffff;
1159                         for(int j = 0; j < am_size; j++) {
1160                                 if(p < track_size) track[p++] = 0xa1;
1161                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1162                         }
1163                         uint8_t am2 = (t[7] != 0) ? 0xf8 : 0xfb;
1164                         if(p < track_size) track[p++] = am2;
1165                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ am2]);
1166                         // data
1167                         for(int j = 0; j < data_size.sd; j++) {
1168                                 if(p < track_size) track[p++] = t[0x10 + j];
1169                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
1170                         }
1171                         if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1172                         if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1173                 }
1174                 t += data_size.sd + 0x10;
1175         }
1176         return true;
1177 }
1178
1179 bool DISK::get_sector(int trk, int side, int index)
1180 {
1181         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1182                 if(trk >= 0) trk >>= 1;
1183         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1184                 if(trk >= 0) trk <<= 1;
1185         }
1186         return get_sector_tmp(trk, side, index);
1187 }
1188
1189 bool DISK::get_sector_tmp(int trk, int side, int index)
1190 {
1191         sector_size.sd = sector_num.sd = 0;
1192         sector = NULL;
1193         
1194         // disk not inserted or invalid media type
1195         if(!(inserted && check_media_type())) {
1196                 return false;
1197         }
1198         
1199         // search track
1200         if(trk == -1 && side == -1) {
1201                 trk = cur_track;
1202                 side = cur_side;
1203         }
1204         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1205         if(!(0 <= trkside && trkside < 164)) {
1206                 return false;
1207         }
1208         pair_t offset;
1209         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1210         
1211         if(!IS_VALID_TRACK(offset.d)) {
1212                 return false;
1213         }
1214         
1215         // track found
1216         uint8_t* t = buffer + offset.d;
1217         sector_num.read_2bytes_le_from(t + 4);
1218         
1219         if(index >= sector_num.sd) {
1220                 return false;
1221         }
1222         
1223         // skip sector
1224         for(int i = 0; i < index; i++) {
1225                 pair_t data_size;
1226                 data_size.read_2bytes_le_from(t + 14);
1227                 t += data_size.sd + 0x10;
1228         }
1229         set_sector_info(t);
1230         return true;
1231 }
1232
1233 void DISK::set_sector_info(uint8_t *t)
1234 {
1235         // header info
1236         int am_size = track_mfm ? 3 : 0;
1237         uint16_t crc = 0xffff;
1238         for(int i = 0; i < am_size; i++) {
1239                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1240         }
1241         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1242         id[0] = t[0];
1243         id[1] = t[1];
1244         id[2] = t[2];
1245         id[3] = t[3];
1246         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1247         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1248         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1249         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1250         id[4] = (crc >> 8) & 0xff;
1251         id[5] = (crc >> 0) & 0xff;
1252         // http://www.gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1253         // t[6]: 0x00 = double-density, 0x40 = single-density
1254         // t[7]: 0x00 = normal, 0x10 = deleted mark
1255         // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1256         density = t[6];
1257         deleted = (t[7] != 0);
1258 //      if(ignore_crc()) {
1259 //              addr_crc_error = false;
1260 //              data_crc_error = false;
1261 //      } else {
1262                 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1263                 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1264 //      }
1265         sector = t + 0x10;
1266         sector_size.read_2bytes_le_from(t + 14);
1267 }
1268
1269 void DISK::set_deleted(bool value)
1270 {
1271         if(sector != NULL) {
1272                 uint8_t *t = sector - 0x10;
1273                 t[7] = value ? 0x10 : 0;
1274                 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1275                         t[8] = (t[8] & 0x0f) | t[7];
1276                 }
1277         }
1278         deleted = value;
1279 }
1280
1281 void DISK::set_data_crc_error(bool value)
1282 {
1283         if(sector != NULL) {
1284                 uint8_t *t = sector - 0x10;
1285                 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1286         }
1287         data_crc_error = value;
1288 }
1289
1290 void DISK::set_data_mark_missing()
1291 {
1292         if(sector != NULL) {
1293                 uint8_t *t = sector - 0x10;
1294                 t[8] = (t[8] & 0x0f) | 0xf0;
1295                 t[14] = t[15] = 0;
1296         }
1297 //      addr_crc_error = false;
1298         data_crc_error = false;
1299 }
1300
1301 bool DISK::format_track(int trk, int side)
1302 {
1303         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1304                 if(trk >= 0) trk >>= 1;
1305         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1306                 if(trk >= 0) trk <<= 1;
1307         }
1308         return format_track_tmp(trk, side);
1309 }
1310
1311 bool DISK::format_track_tmp(int trk, int side)
1312 {
1313         // disk not inserted or invalid media type
1314         if(!(inserted && check_media_type())) {
1315                 return false;
1316         }
1317         
1318         // search track
1319         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1320         if(!(0 <= trkside && trkside < 164)) {
1321                 return false;
1322         }
1323         
1324         // create new empty track
1325         if(trim_required) {
1326                 trim_buffer();
1327                 trim_required = false;
1328         }
1329         memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1330         pair_t offset;
1331         offset.d = DISK_BUFFER_SIZE;
1332         offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1333         
1334         trim_required = true;
1335         sector_num.sd = 0;
1336         track_mfm = drive_mfm;
1337         
1338         return true;
1339 }
1340
1341 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)
1342 {
1343         uint8_t* t = buffer + DISK_BUFFER_SIZE;
1344         
1345         sector_num.sd++;
1346         for(int i = 0; i < (sector_num.sd - 1); i++) {
1347                 t[4] = sector_num.b.l;
1348                 t[5] = sector_num.b.h;
1349                 pair_t data_size;
1350                 data_size.read_2bytes_le_from(t + 14);
1351                 t += data_size.sd + 0x10;
1352         }
1353         t[0] = c;
1354         t[1] = h;
1355         t[2] = r;
1356         t[3] = n;
1357         t[4] = sector_num.b.l;
1358         t[5] = sector_num.b.h;
1359         t[6] = track_mfm ? 0 : 0x40;
1360         t[7] = deleted ? 0x10 : 0;
1361         t[8] = data_crc_error ? 0xb0 : t[7];
1362         t[14] = (length >> 0) & 0xff;
1363         t[15] = (length >> 8) & 0xff;
1364         memset(t + 16, fill_data, length);
1365         
1366         set_sector_info(t);
1367 }
1368
1369 void DISK::sync_buffer()
1370 {
1371         if(trim_required) {
1372                 trim_buffer();
1373                 trim_required = false;
1374         }
1375 }
1376
1377 void DISK::trim_buffer()
1378 {
1379         int max_tracks = 164;
1380         int track_limit = 164;
1381         uint32_t dest_offset = 0x2b0;
1382         
1383         // copy header
1384         memset(tmp_buffer, 0, sizeof(tmp_buffer));
1385         memcpy(tmp_buffer, buffer, 0x20);
1386         
1387         // check max tracks
1388         if(media_type == MEDIA_TYPE_2D) {
1389                 track_limit = 84;
1390         }
1391         for(int trkside = 0; trkside < 164; trkside++) {
1392                 pair_t src_trk_offset;
1393                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1394                 if(src_trk_offset.d != 0) {
1395 #if 1
1396                         if(src_trk_offset.d < 0x2b0) {
1397                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1398                                 if(max_tracks > track_limit) {
1399                                         max_tracks = track_limit;
1400                                 }
1401                         }
1402 #else
1403                         if(src_trk_offset.d != 0x2b0) {
1404                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1405                                 if(max_tracks > 164) {
1406                                         dest_offset = 0x20 + max_tracks * 4);
1407                                 }
1408                         }
1409 #endif
1410                         break;
1411                 }
1412         }
1413         
1414         // copy tracks
1415         for(int trkside = 0; trkside < max_tracks; trkside++) {
1416                 pair_t src_trk_offset;
1417                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1418                 
1419                 pair_t dest_trk_offset;
1420                 dest_trk_offset.d = 0;
1421                 
1422                 if(IS_VALID_TRACK(src_trk_offset.d)) {
1423                         uint8_t* t = buffer + src_trk_offset.d;
1424                         pair_t sector_num, data_size;
1425                         sector_num.read_2bytes_le_from(t + 4);
1426                         if(sector_num.sd != 0) {
1427                                 dest_trk_offset.d = dest_offset;
1428                                 for(int i = 0; i < sector_num.sd; i++) {
1429                                         data_size.read_2bytes_le_from(t + 14);
1430                                         memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1431                                         dest_offset += data_size.sd + 0x10;
1432                                         t += data_size.sd + 0x10;
1433                                 }
1434                         }
1435                 }
1436                 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1437         }
1438         
1439         // update file size
1440         file_size.d = dest_offset;
1441         file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1442         
1443         memset(buffer, 0, sizeof(buffer));
1444         memcpy(buffer, tmp_buffer, min((unsigned int)sizeof(buffer), file_size.d));
1445 }
1446
1447 int DISK::get_max_tracks()
1448 {
1449         if(drive_type != DRIVE_TYPE_UNK) {
1450                 return (drive_type != DRIVE_TYPE_2D) ? 84 : 42;
1451         } else if(inserted) {
1452                 return (media_type != MEDIA_TYPE_2D) ? 84 : 42;
1453         } else {
1454                 return 84; // 2DD or 2HD
1455         }
1456 }
1457
1458 int DISK::get_rpm()
1459 {
1460         if(drive_rpm != 0) {
1461                 return drive_rpm;
1462         } else if(inserted) {
1463                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1464         } else {
1465                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1466         }
1467 }
1468
1469 int DISK::get_track_size()
1470 {
1471         if(track_size != 0) {
1472                 return track_size;
1473         } else if(inserted) {
1474                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1475         } else {
1476                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1477         }
1478 }
1479
1480 double DISK::get_usec_per_track()
1481 {
1482         return 1000000.0 / (get_rpm() / 60.0);
1483 }
1484
1485 double DISK::get_usec_per_bytes(int bytes)
1486 {
1487         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1488 }
1489
1490 int DISK::get_bytes_per_usec(double usec)
1491 {
1492         return (int)(usec / get_usec_per_bytes(1) + 0.5);
1493 }
1494
1495 bool DISK::check_media_type()
1496 {
1497         switch(drive_type) {
1498         case DRIVE_TYPE_2D:
1499                         return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1500         case DRIVE_TYPE_2DD:
1501                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1502         case DRIVE_TYPE_2HD:
1503                 return (media_type == MEDIA_TYPE_2HD);
1504         case DRIVE_TYPE_144:
1505                 return (media_type == MEDIA_TYPE_144);
1506         case DRIVE_TYPE_UNK:
1507                 return true; // always okay
1508         }
1509         return false;
1510 }
1511
1512 // image decoder
1513
1514 #define COPYBUFFER(src, size) { \
1515         if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1516                 return false; \
1517         } \
1518         memcpy(buffer + file_size.d, (src), (size)); \
1519         file_size.d += (size); \
1520 }
1521
1522 typedef struct {
1523         char title[17];
1524         uint8_t rsrv[9];
1525         uint8_t protect;
1526         uint8_t type;
1527         uint32_t size;
1528         uint32_t trkptr[164];
1529 } d88_hdr_t;
1530
1531 typedef struct {
1532         uint8_t c, h, r, n;
1533         uint16_t nsec;
1534         uint8_t dens, del, stat;
1535         uint8_t rsrv[5];
1536         uint16_t size;
1537 } d88_sct_t;
1538
1539 // teledisk image decoder
1540
1541 /*
1542         this teledisk image decoder is based on:
1543         
1544                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1545                 LZSS coded by Haruhiko OKUMURA
1546                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1547                 Edited and translated to English by Kenji RIKITAKE
1548                 TDLZHUF.C by WTK
1549 */
1550
1551 #define STRING_BUFFER_SIZE      4096
1552 #define LOOKAHEAD_BUFFER_SIZE   60
1553 #define THRESHOLD               2
1554 #define N_CHAR                  (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1555 #define TABLE_SIZE              (N_CHAR * 2 - 1)
1556 #define ROOT_POSITION           (TABLE_SIZE - 1)
1557 #define MAX_FREQ                0x8000
1558
1559 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1560 static uint16_t td_ptr;
1561 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1562 static uint16_t td_ibufcnt, td_ibufndx;
1563 static uint8_t td_inbuf[512];
1564 static uint16_t td_freq[TABLE_SIZE + 1];
1565 static short td_prnt[TABLE_SIZE + N_CHAR];
1566 static short td_son[TABLE_SIZE];
1567 static uint16_t td_getbuf;
1568 static uint8_t td_getlen;
1569
1570 static const uint8_t td_d_code[256] = {
1571         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1572         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1573         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1574         0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1575         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1576         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1577         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1578         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1579         0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1580         0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1581         0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1582         0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1583         0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1584         0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1585         0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1586         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1587 };
1588 static const uint8_t td_d_len[256] = {
1589         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1590         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1591         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1592         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1593         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1594         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1595         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1596         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1597         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1598         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1599         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1600         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1601         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1602         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1603         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1604         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1605 };
1606
1607 static int td_next_word(FILEIO* fio)
1608 {
1609         if(td_ibufndx >= td_ibufcnt) {
1610                 td_ibufndx = td_ibufcnt = 0;
1611                 memset(td_inbuf, 0, 512);
1612                 for(int i = 0; i < 512; i++) {
1613                         int d = fio->Fgetc();
1614                         if(d == EOF) {
1615                                 if(i) {
1616                                         break;
1617                                 }
1618                                 return(-1);
1619                         }
1620                         td_inbuf[i] = d;
1621                         td_ibufcnt = i + 1;
1622                 }
1623         }
1624         while(td_getlen <= 8) {
1625                 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1626                 td_getlen += 8;
1627         }
1628         return 0;
1629 }
1630
1631 static int td_get_bit(FILEIO* fio)
1632 {
1633         if(td_next_word(fio) < 0) {
1634                 return -1;
1635         }
1636         short i = td_getbuf;
1637         td_getbuf <<= 1;
1638         td_getlen--;
1639         return (i < 0) ? 1 : 0;
1640 }
1641
1642 static int td_get_byte(FILEIO* fio)
1643 {
1644         if(td_next_word(fio) != 0) {
1645                 return -1;
1646         }
1647         uint16_t i = td_getbuf;
1648         td_getbuf <<= 8;
1649         td_getlen -= 8;
1650         i >>= 8;
1651         return (int)i;
1652 }
1653
1654 static void td_start_huff()
1655 {
1656         int i, j;
1657         for(i = 0; i < N_CHAR; i++) {
1658                 td_freq[i] = 1;
1659                 td_son[i] = i + TABLE_SIZE;
1660                 td_prnt[i + TABLE_SIZE] = i;
1661         }
1662         i = 0; j = N_CHAR;
1663         while(j <= ROOT_POSITION) {
1664                 td_freq[j] = td_freq[i] + td_freq[i + 1];
1665                 td_son[j] = i;
1666                 td_prnt[i] = td_prnt[i + 1] = j;
1667                 i += 2; j++;
1668         }
1669         td_freq[TABLE_SIZE] = 0xffff;
1670         td_prnt[ROOT_POSITION] = 0;
1671 }
1672
1673 static void td_reconst()
1674 {
1675         short i, j = 0, k;
1676         uint16_t f, l;
1677         for(i = 0; i < TABLE_SIZE; i++) {
1678                 if(td_son[i] >= TABLE_SIZE) {
1679                         td_freq[j] = (td_freq[i] + 1) / 2;
1680                         td_son[j] = td_son[i];
1681                         j++;
1682                 }
1683         }
1684         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1685                 k = i + 1;
1686                 f = td_freq[j] = td_freq[i] + td_freq[k];
1687                 for(k = j - 1; f < td_freq[k]; k--);
1688                 k++;
1689                 l = (j - k) * 2;
1690                 memmove(&td_freq[k + 1], &td_freq[k], l);
1691                 td_freq[k] = f;
1692                 memmove(&td_son[k + 1], &td_son[k], l);
1693                 td_son[k] = i;
1694         }
1695         for(i = 0; i < TABLE_SIZE; i++) {
1696                 if((k = td_son[i]) >= TABLE_SIZE) {
1697                         td_prnt[k] = i;
1698                 } else {
1699                         td_prnt[k] = td_prnt[k + 1] = i;
1700                 }
1701         }
1702 }
1703
1704 static void td_update(int c)
1705 {
1706         int i, j, k, l;
1707         if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1708                 td_reconst();
1709         }
1710         c = td_prnt[c + TABLE_SIZE];
1711         do {
1712                 k = ++td_freq[c];
1713                 if(k > td_freq[l = c + 1]) {
1714                         while(k > td_freq[++l]);
1715                         l--;
1716                         td_freq[c] = td_freq[l];
1717                         td_freq[l] = k;
1718                         i = td_son[c];
1719                         td_prnt[i] = l;
1720                         if(i < TABLE_SIZE) {
1721                                 td_prnt[i + 1] = l;
1722                         }
1723                         j = td_son[l];
1724                         td_son[l] = i;
1725                         td_prnt[j] = c;
1726                         if(j < TABLE_SIZE) {
1727                                 td_prnt[j + 1] = c;
1728                         }
1729                         td_son[c] = j;
1730                         c = l;
1731                 }
1732         }
1733         while((c = td_prnt[c]) != 0);
1734 }
1735
1736 static short td_decode_char(FILEIO* fio)
1737 {
1738         int ret;
1739         uint16_t c = td_son[ROOT_POSITION];
1740         while(c < TABLE_SIZE) {
1741                 if((ret = td_get_bit(fio)) < 0) {
1742                         return -1;
1743                 }
1744                 c += (unsigned)ret;
1745                 c = td_son[c];
1746         }
1747         c -= TABLE_SIZE;
1748         td_update(c);
1749         return c;
1750 }
1751
1752 static short td_decode_position(FILEIO* fio)
1753 {
1754         short bit;
1755         uint16_t i, j, c;
1756         if((bit = td_get_byte(fio)) < 0) {
1757                 return -1;
1758         }
1759         i = (uint16_t)bit;
1760         c = (uint16_t)td_d_code[i] << 6;
1761         j = td_d_len[i] - 2;
1762         while(j--) {
1763                 if((bit = td_get_bit(fio)) < 0) {
1764                          return -1;
1765                 }
1766                 i = (i << 1) + bit;
1767         }
1768         return (c | (i & 0x3f));
1769 }
1770
1771 static void td_init_decode()
1772 {
1773         td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1774         td_getlen = 0;
1775         td_start_huff();
1776         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1777                 td_text_buf[i] = ' ';
1778         }
1779         td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1780 }
1781
1782 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1783 {
1784         short c, pos;
1785         int  count;
1786         for(count = 0; count < len;) {
1787                 if(td_bufcnt == 0) {
1788                         if((c = td_decode_char(fio)) < 0) {
1789                                 return count;
1790                         }
1791                         if(c < 256) {
1792                                 *(buf++) = (uint8_t)c;
1793                                 td_text_buf[td_ptr++] = (uint8_t)c;
1794                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1795                                 count++;
1796                         } else {
1797                                 if((pos = td_decode_position(fio)) < 0) {
1798                                         return count;
1799                                 }
1800                                 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1801                                 td_bufcnt = c - 255 + THRESHOLD;
1802                                 td_bufndx = 0;
1803                         }
1804                 } else {
1805                         while(td_bufndx < td_bufcnt && count < len) {
1806                                 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1807                                 *(buf++) = (uint8_t)c;
1808                                 td_bufndx++;
1809                                 td_text_buf[td_ptr++] = (uint8_t)c;
1810                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1811                                 count++;
1812                         }
1813                         if(td_bufndx >= td_bufcnt) {
1814                                 td_bufndx = td_bufcnt = 0;
1815                         }
1816                 }
1817         }
1818         return count;
1819 }
1820
1821 typedef struct {
1822         char sig[3];
1823         uint8_t unknown;
1824         uint8_t ver;
1825         uint8_t dens;
1826         uint8_t type;
1827         uint8_t flag;
1828         uint8_t dos;
1829         uint8_t sides;
1830         uint16_t crc;
1831 } td_hdr_t;
1832
1833 typedef struct {
1834         uint16_t crc;
1835         uint16_t len;
1836         uint8_t ymd[3];
1837         uint8_t hms[3];
1838 } td_cmt_t;
1839
1840 typedef struct {
1841         uint8_t nsec, trk, head;
1842         uint8_t crc;
1843 } td_trk_t;
1844
1845 typedef struct {
1846         uint8_t c, h, r, n;
1847         uint8_t ctrl, crc;
1848 } td_sct_t;
1849
1850 bool DISK::teledisk_to_d88(FILEIO *fio)
1851 {
1852         td_hdr_t hdr;
1853         td_cmt_t cmt;
1854         td_trk_t trk;
1855         td_sct_t sct;
1856         uint8_t obuf[512];
1857         bool temporary = false;
1858         
1859         // check teledisk header
1860         fio->Fseek(0, FILEIO_SEEK_SET);
1861         fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1862         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1863                 // this image is compressed
1864                 // decompress to the temporary file
1865                 FILEIO* fio_tmp = new FILEIO();
1866                 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1867                         delete fio_tmp;
1868                         return false;
1869                 }
1870                 int rd = 1;
1871                 td_init_decode();
1872                 do {
1873                         if((rd = td_decode(fio, obuf, 512)) > 0) {
1874                                 fio_tmp->Fwrite(obuf, rd, 1);
1875                         }
1876                 }
1877                 while(rd > 0);
1878                 fio_tmp->Fclose();
1879                 delete fio_tmp;
1880                 temporary = true;
1881                 
1882                 // reopen the temporary file
1883                 fio->Fclose();
1884                 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1885                         return false;
1886                 }
1887         } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1888                 // this image is not compressed
1889         } else {
1890                 return false;
1891         }
1892         if(hdr.flag & 0x80) {
1893                 // skip comment
1894                 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1895                 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1896         }
1897         
1898         // create d88 header
1899         d88_hdr_t d88_hdr;
1900         d88_sct_t d88_sct;
1901         
1902         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1903         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1904         d88_hdr.protect = 0; // non-protected
1905         
1906         file_size.d = 0;
1907         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1908         
1909         // create tracks
1910         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1911         fio->Fread(&trk, sizeof(td_trk_t), 1);
1912         while(trk.nsec != 0xff) {
1913                 d88_hdr.trkptr[trkcnt++] = trkptr;
1914                 if(hdr.sides == 1) {
1915                         trkcnt++;
1916                 }
1917                 
1918                 // read sectors in this track
1919                 for(int i = 0; i < trk.nsec; i++) {
1920                         uint8_t buf[2048], dst[2048];
1921                         memset(buf, 0, sizeof(buf));
1922                         memset(dst, 0, sizeof(dst));
1923                         
1924                         // read sector header
1925                         fio->Fread(&sct, sizeof(td_sct_t), 1);
1926                         
1927                         // create d88 sector header
1928                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1929                         d88_sct.c = sct.c;
1930                         d88_sct.h = sct.h;
1931                         d88_sct.r = sct.r;
1932                         d88_sct.n = sct.n;
1933                         d88_sct.nsec = trk.nsec;
1934                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1935                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1936                         d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1937                         d88_sct.size = secsize[sct.n & 3];
1938                         
1939                         // create sector image
1940                         if(sct.ctrl & 0x30) {
1941                                 d88_sct.stat = 0xf0; // data mark missing
1942                                 d88_sct.size = 0;
1943                         } else {
1944                                 // read sector source
1945                                 int len = fio->Fgetc();
1946                                 len += fio->Fgetc() * 256 - 1;
1947                                 int flag = fio->Fgetc(), d = 0;
1948                                 fio->Fread(buf, len, 1);
1949                                 
1950                                 // convert
1951                                 if(flag == 0) {
1952                                         memcpy(dst, buf, len);
1953                                 } else if(flag == 1) {
1954                                         pair_t len2;
1955                                         len2.read_2bytes_le_from(buf);
1956                                         while(len2.sd--) {
1957                                                 dst[d++] = buf[2];
1958                                                 dst[d++] = buf[3];
1959                                         }
1960                                 } else if(flag == 2) {
1961                                         for(int s = 0; s < len;) {
1962                                                 int type = buf[s++];
1963                                                 int len2 = buf[s++];
1964                                                 if(type == 0) {
1965                                                         while(len2--) {
1966                                                                 dst[d++] = buf[s++];
1967                                                         }
1968                                                 } else if(type < 5) {
1969                                                         uint8_t pat[256];
1970                                                         int n = 2;
1971                                                         while(type-- > 1) {
1972                                                                 n *= 2;
1973                                                         }
1974                                                         for(int j = 0; j < n; j++) {
1975                                                                 pat[j] = buf[s++];
1976                                                         }
1977                                                         while(len2--) {
1978                                                                 for(int j = 0; j < n; j++) {
1979                                                                         dst[d++] = pat[j];
1980                                                                 }
1981                                                         }
1982                                                 } else {
1983                                                         break; // unknown type
1984                                                 }
1985                                         }
1986                                 } else {
1987                                         break; // unknown flag
1988                                 }
1989                         }
1990                         
1991                         // copy to d88
1992                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1993                         COPYBUFFER(dst, d88_sct.size);
1994                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1995                 }
1996                 // read next track
1997                 fio->Fread(&trk, sizeof(td_trk_t), 1);
1998         }
1999         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
2000         d88_hdr.size = trkptr;
2001         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2002         
2003         if(temporary) {
2004                 FILEIO::RemoveFile(_T("teledisk.$$$"));
2005         }
2006         return true;
2007 }
2008
2009 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
2010
2011 bool DISK::imagedisk_to_d88(FILEIO *fio)
2012 {
2013         int size = fio->FileLength();
2014         fio->Fseek(0, FILEIO_SEEK_SET);
2015         fio->Fread(tmp_buffer, size, 1);
2016         
2017         if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
2018                 return false;
2019         }
2020         
2021         int pos;
2022         for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
2023         pos++;
2024         
2025         if(pos >= size) {
2026                 return false;
2027         }
2028         
2029         // create d88 header
2030         d88_hdr_t d88_hdr;
2031         d88_sct_t d88_sct;
2032         
2033         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2034         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
2035         d88_hdr.protect = 0; // non-protected
2036         
2037         file_size.d = 0;
2038         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2039         
2040         // create tracks
2041         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
2042         int img_mode = -1;
2043         uint8_t dst[8192];
2044         
2045         while(pos < size) {
2046                 // check track header
2047                 uint8_t mode = tmp_buffer[pos++];
2048                 uint8_t track = tmp_buffer[pos++];
2049                 uint8_t head = tmp_buffer[pos++];
2050                 uint8_t sector_count = tmp_buffer[pos++];
2051                 uint8_t ssize = tmp_buffer[pos++];
2052                 
2053                 if(sector_count == 0) {
2054                         continue;
2055                 }
2056                 if(ssize == 0xff) {
2057                         return false;
2058                 }
2059                 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
2060                 
2061                 // setup sector id
2062                 const uint8_t *snum = &tmp_buffer[pos];
2063                 pos += sector_count;
2064                 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
2065                 if(tnum)
2066                         pos += sector_count;
2067                 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
2068                 if(hnum)
2069                         pos += sector_count;
2070                 head &= 0x3f;
2071                 
2072                 // create new track
2073                 int trkside = track * 2 + (head & 1);
2074                 if(trkside < 164) {
2075                         if(trkcnt < trkside) {
2076                                 trkcnt = trkside;
2077                         }
2078                         d88_hdr.trkptr[trkside] = trkptr;
2079                 }
2080                 if(img_mode == -1) {
2081                         img_mode = mode & 3;
2082                 }
2083                 
2084                 // read sectors in this track
2085                 for(int i = 0; i < sector_count; i++) {
2086                         // create d88 sector header
2087                         uint8_t stype = tmp_buffer[pos++];
2088                         memset(&d88_sct, 0, sizeof(d88_sct_t));
2089                         d88_sct.c = tnum ? tnum[i] : track;
2090                         d88_sct.h = hnum ? hnum[i] : head;
2091                         d88_sct.r = snum[i];
2092                         d88_sct.n = ssize;
2093                         d88_sct.nsec = sector_count;
2094                         d88_sct.dens = (mode < 3) ? 0x40 : 0;
2095                         
2096                         if(stype == 0 || stype > 8) {
2097                                 d88_sct.stat = 0xf0; // data mark missing
2098                                 d88_sct.size = 0;
2099                         } else {
2100                                 d88_sct.del  = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
2101                                 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
2102                                 d88_sct.size = actual_size;
2103                                 
2104                                 // create sector image
2105                                 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
2106                                         memset(dst, tmp_buffer[pos++], actual_size);
2107                                 } else {
2108                                         memcpy(dst, &tmp_buffer[pos], actual_size);
2109                                         pos += d88_sct.size;
2110                                 }
2111                         }
2112                         
2113                         // copy to d88
2114                         if(trkside < 164) {
2115                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2116                                 COPYBUFFER(dst, d88_sct.size);
2117                                 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2118                         }
2119                 }
2120         }
2121         d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
2122         d88_hdr.size = trkptr;
2123         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2124         return true;
2125 }
2126
2127 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
2128
2129 #define DSK_FORMAT_HEADER       "MV - CPC"
2130 #define EXT_FORMAT_HEADER       "EXTENDED CPC DSK"
2131
2132 #pragma pack(1)
2133 struct track_header {
2134         uint8_t headertag[13];
2135         uint16_t unused1;
2136         uint8_t unused1b;
2137         uint8_t track_number;
2138         uint8_t side_number;
2139         uint8_t datarate;
2140         uint8_t rec_mode;
2141         uint8_t sector_size_code;
2142         uint8_t number_of_sector;
2143         uint8_t gap3_length;
2144         uint8_t filler_byte;
2145 };
2146 struct sector_header {
2147         uint8_t track;
2148         uint8_t side;
2149         uint8_t sector_id;
2150         uint8_t sector_size_code;
2151         uint8_t fdc_status_reg1;
2152         uint8_t fdc_status_reg2;
2153         uint16_t data_length;
2154 };
2155 #pragma pack()
2156
2157 bool DISK::cpdread_to_d88(FILEIO *fio)
2158 {
2159         bool extendformat = false;
2160         int image_size = fio->FileLength();
2161         
2162         fio->Fseek(0, FILEIO_SEEK_SET);
2163         fio->Fread(tmp_buffer, image_size, 1);
2164         
2165         if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
2166                 extendformat = true;
2167         } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
2168                 extendformat = false;
2169         } else {
2170                 return false;
2171         }
2172         
2173         int heads = tmp_buffer[0x31];
2174         int skip = 1;
2175         if(heads == 1) {
2176                 skip = 2;
2177         }
2178         int tracks = tmp_buffer[0x30];
2179         int track_offsets[84 * 2];
2180         bool track_offsets_error = false;
2181         if(!extendformat) {
2182                 int cnt = 0, tmp = 0x100;
2183                 for(int i = 0; i < tracks * heads; i++) {
2184                         track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2185                         if(track_offsets_error) {
2186                                 break;
2187                         }
2188                         track_offsets[cnt] = tmp;
2189                         tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
2190                         cnt += skip;
2191                 }
2192         } else  {
2193                 int cnt = 0, tmp = 0x100;
2194                 for(int i = 0; i < tracks * heads; i++) {
2195                         int length = tmp_buffer[0x34 + i] << 8;
2196                         if(length != 0) {
2197                                 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2198                                 if(track_offsets_error) {
2199                                         break;
2200                                 }
2201                                 track_offsets[cnt] = tmp;
2202                                 tmp += length;
2203                         } else {
2204                                 track_offsets[cnt] = image_size;
2205                         }
2206                         cnt += skip;
2207                 }
2208         }
2209         if(track_offsets_error) {
2210                 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
2211                 // so I modified this code to search "Track-Info" at the top of track information block
2212                 int cnt = 0, tmp = 0x100;
2213                 for(int i = 0; i < tracks * heads; i++) {
2214                         bool found = false;
2215                         for(; tmp < image_size; tmp += 0x10) {
2216                                 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
2217                                 if(found) {
2218                                         break;
2219                                 }
2220                         }
2221                         if(found) {
2222                                 track_offsets[cnt] = tmp;
2223                                 tmp += 0x10;
2224                         } else {
2225                                 track_offsets[cnt] = image_size;
2226                         }
2227                         cnt += skip;
2228                 }
2229         }
2230         
2231         // create d88 header
2232         d88_hdr_t d88_hdr;
2233         d88_sct_t d88_sct;
2234         
2235         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2236         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
2237         d88_hdr.protect = 0; // non-protected
2238         
2239         file_size.d = 0;
2240         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2241         
2242         // create tracks
2243         int total = 0, trkptr = sizeof(d88_hdr_t);
2244         
2245         for(int track = 0; track < tracks; track++) {
2246                 for(int side = 0; side < heads; side++) {
2247                         if(track_offsets[(track << 1) + side] >= image_size) {
2248                                 continue;
2249                         }
2250                         if((track << 1) + side < 164) {
2251                                 d88_hdr.trkptr[(track << 1) + side] = trkptr;
2252                         }
2253                         
2254                         track_header tr;
2255                         memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
2256                         int pos = track_offsets[(track << 1) + side] + 0x100;
2257                         for(int j = 0; j < tr.number_of_sector; j++) {
2258                                 sector_header sector;
2259                                 memcpy(&sector, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2260                                 
2261                                 // create d88 sector header
2262                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2263                                 d88_sct.c = sector.track;
2264                                 d88_sct.h = sector.side;
2265                                 d88_sct.r = sector.sector_id;
2266                                 d88_sct.n = sector.sector_size_code;
2267                                 d88_sct.nsec = tr.number_of_sector;
2268                                 if(extendformat) {
2269                                         d88_sct.size = sector.data_length;
2270                                         d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2271                                 } else {
2272                                         d88_sct.size = 128 << tr.sector_size_code;
2273                                         d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2274                                 }
2275                                 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2276                                 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2277                                 
2278                                 // copy to d88
2279                                 if((track << 1) + side < 164) {
2280                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2281                                         COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2282                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2283                                 }
2284                                 total += d88_sct.size;
2285                                 
2286                                 if(extendformat) {
2287                                         pos += sector.data_length;
2288                                 } else {
2289                                         pos += 128 << tr.sector_size_code;
2290                                 }
2291                         }
2292                 }
2293         }
2294         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2295         d88_hdr.size = trkptr;
2296         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2297         return true;
2298 }
2299
2300 // nfd r0/r1 image decoder
2301
2302 bool DISK::nfdr0_to_d88(FILEIO *fio)
2303 {
2304         // from NFD r0\8c`\8e®\83t\83@\83C\83\8b\8d\\91¢\8ed\97l 2001/01/22 LED
2305         typedef struct {
2306             BYTE  C;                            // C \81i0xFF\82Ì\8e\9e\83Z\83N\83^\96³\82µ\81j
2307             BYTE  H;                            // H
2308             BYTE  R;                            // R
2309             BYTE  N;                            // N
2310             BYTE  flMFM;                        // 0:FM / 1:MFM
2311             BYTE  flDDAM;                       // 0:DAM / 1:DDAM
2312             BYTE  byStatus;                     // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê
2313             BYTE  byST0;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST0
2314             BYTE  byST1;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST1
2315             BYTE  byST2;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST2
2316             BYTE  byPDA;                        // FDDBIOS\82Å\8eg\97p\82·\82é\83A\83h\83\8c\83X
2317             char Reserve1[5];                   // \97\\96ñ
2318         }NFD_SECT_ID,*LP_NFD_SECT_ID;
2319         
2320         typedef struct {
2321             char  szFileID[15];                 // \8e¯\95ÊID "T98FDDIMAGE.R0"
2322             char  Reserve1[1];                  // \97\\96ñ
2323             char  szComment[0x100];             // \83C\83\81\81[\83W\83R\83\81\83\93\83g(ASCIIz)
2324             DWORD dwHeadSize;                   // \83w\83b\83_\95\94\82Ì\83T\83C\83Y
2325             BYTE  flProtect;                    // 0\88È\8aO : \83\89\83C\83g\83v\83\8d\83e\83N\83g
2326             BYTE  byHead;                       // \83w\83b\83h\90\94
2327             char  Reserve2[10];                 // \97\\96ñ
2328             NFD_SECT_ID si[163][26];            // \83Z\83N\83^ID(\8cã\8fq)
2329             char  Reserve3[0x10];               // \97\\96ñ
2330         }NFD_FILE_HEAD,*LP_NFD_FILE_HEAD;
2331         
2332         // check nfd header
2333         NFD_FILE_HEAD head;
2334         
2335         fio->Fseek(0, FILEIO_SEEK_SET);
2336         fio->Fread(&head, sizeof(head), 1);
2337         
2338         if(strncmp(head.szFileID, "T98FDDIMAGE.R0", 14) != 0) {
2339                 return false;
2340         }
2341         fio->Fseek(head.dwHeadSize, FILEIO_SEEK_SET);
2342         
2343         // create d88 header
2344         d88_hdr_t d88_hdr;
2345         d88_sct_t d88_sct;
2346         
2347         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2348         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "NFD R0");
2349         d88_hdr.protect = head.flProtect;
2350         
2351         file_size.d = 0;
2352         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2353         
2354         // create tracks
2355         int trkptr = sizeof(d88_hdr_t);
2356         
2357         for(int c = 0; c < 163; c++) {
2358                 int nsec = 0;
2359                 
2360                 for(int s = 0; s < 26; s++) {
2361                         if(head.si[c][s].C != 0xff) {
2362                                 nsec++;
2363                         }
2364                 }
2365                 if(nsec) {
2366                         d88_hdr.trkptr[c] = trkptr;
2367                         
2368                         // read sectors in this track
2369                         for(int s = 0; s < 26; s++) {
2370                                 if(head.si[c][s].C != 0xff) {
2371                                         // create d88 sector header
2372                                         memset(&d88_sct, 0, sizeof(d88_sct_t));
2373                                         d88_sct.c = head.si[c][s].C;
2374                                         d88_sct.h = head.si[c][s].H;
2375                                         d88_sct.r = head.si[c][s].R;
2376                                         d88_sct.n = head.si[c][s].N;
2377                                         d88_sct.nsec = nsec;
2378                                         d88_sct.dens = head.si[c][s].flMFM ? 0 : 0x40;
2379                                         d88_sct.del = head.si[c][s].flDDAM ? 0x10 : 0;
2380                                         if(head.si[c][s].byST1 & 0x20) {
2381                                                 if(head.si[c][s].byST2 & 0x20) {
2382                                                         d88_sct.stat = 0xb0; // data crc error
2383                                                 } else {
2384                                                         d88_sct.stat = 0xa0; // id crc error
2385                                                 }
2386                                         } else if(head.si[c][s].byST1 & 0x01) {
2387                                                 d88_sct.stat = 0xe0; // address mark missing
2388                                         } else if(head.si[c][s].byST2 & 0x01) {
2389                                                 d88_sct.stat = 0xf0; // data mark missing
2390                                         } else {
2391                                                 d88_sct.stat = d88_sct.del;
2392                                         }
2393                                         d88_sct.size = secsize[d88_sct.n & 3];
2394                                         
2395                                         // create sector image
2396                                         uint8_t dst[16384];
2397                                         memset(dst, 0xe5, sizeof(dst));
2398                                         fio->Fread(dst, d88_sct.size, 1);
2399                                         
2400                                         // copy to d88
2401                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2402                                         COPYBUFFER(dst, d88_sct.size);
2403                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2404                                         
2405                                         if(head.si[c][s].byPDA == 0x10) {
2406                                                 d88_hdr.type = MEDIA_TYPE_2DD;
2407                                         } else {
2408                                                 d88_hdr.type = MEDIA_TYPE_2HD;
2409                                         }
2410                                 }
2411                         }
2412                 }
2413         }
2414         d88_hdr.size = trkptr;
2415         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2416         return true;
2417 }
2418
2419 bool DISK::nfdr1_to_d88(FILEIO *fio)
2420 {
2421         // from NFD r1\8c`\8e®\83t\83@\83C\83\8b\8d\\91¢\8ed\97l 2001/09/14 LED
2422         typedef struct {
2423 //          char szFileID[sizeof(NFD_FILE_ID1)];        /* \8e¯\95ÊID "T98FDDIMAGE.R1"  */
2424 //          char Reserv1[0x10-sizeof(NFD_FILE_ID1)];    /* \97\\94õ                     */
2425             char  szFileID[15];                         /* \8e¯\95ÊID "T98FDDIMAGE.R1"  */
2426             char  Reserve1[1];                          /* \97\\96ñ                     */
2427             char szComment[0x100];                      /* \83R\83\81\83\93\83g                 */
2428             DWORD dwHeadSize;                           /* \83w\83b\83_\82Ì\83T\83C\83Y           */
2429             BYTE flProtect;                             /* \83\89\83C\83g\83v\83\8d\83e\83N\83g0\88È\8aO    */
2430             BYTE byHead;                                /* \83w\83b\83h\90\94 1-2             */
2431             char Reserv2[0x10-4-1-1];                   /* \97\\94õ                     */
2432             DWORD dwTrackHead[164];                     /* \83g\83\89\83b\83NID\88Ê\92u           */
2433             DWORD dwAddInfo;                            /* \92Ç\89Á\8fî\95ñ\83w\83b\83_\82Ì\83A\83h\83\8c\83X */
2434             char Reserv3[0x10-4];                       /* \97\\94õ                     */
2435         }NFD_FILE_HEAD1,*LP_NFD_FILE_HEAD1;
2436         
2437         typedef struct {
2438             WORD wSector;                               /* \83Z\83N\83^ID\90\94               */
2439             WORD wDiag;                                 /* \93Á\8eê ID\90\94                */
2440             char Reserv1[0x10-4];                       /* \97\\94õ                     */
2441         }NFD_TRACK_ID1,*LP_NFD_TRACK_ID1;
2442         
2443         typedef struct {
2444             BYTE    C;                                  /* C                        */
2445             BYTE    H;                                  /* H                        */
2446             BYTE    R;                                  /* R                        */
2447             BYTE    N;                                  /* N                        */
2448             BYTE    flMFM;                              /* MFM(1)/FM(0)             */
2449             BYTE    flDDAM;                             /* DDAM(1)/DAM(0)           */
2450             BYTE    byStatus;                           /* READ DATA RESULT         */
2451             BYTE    bySTS0;                             /* ST0                      */
2452             BYTE    bySTS1;                             /* ST1                      */
2453             BYTE    bySTS2;                             /* ST2                      */
2454             BYTE    byRetry;                            /* RetryData\82È\82µ(0)\82 \82è(1-) */
2455             BYTE    byPDA;                              /* PDA                      */
2456             char Reserv1[0x10-12];                      /* \97\\94õ                     */
2457         }NFD_SECT_ID1,*LP_NFD_SECT_ID1;
2458         
2459         typedef struct {
2460             BYTE    Cmd;                                /* Command                  */
2461             BYTE    C;                                  /* C                        */
2462             BYTE    H;                                  /* H                        */
2463             BYTE    R;                                  /* R                        */
2464             BYTE    N;                                  /* N                        */
2465             BYTE    byStatus;                           /* READ DATA RESULT         */
2466             BYTE    bySTS0;                             /* ST0                      */
2467             BYTE    bySTS1;                             /* ST1                      */
2468             BYTE    bySTS2;                             /* ST2                      */
2469             BYTE    byRetry;                            /* RetryData\82È\82µ(0)\82 \82è(1-) */
2470             DWORD   dwDataLen;
2471             BYTE    byPDA;                              /* PDA                      */
2472             char Reserv1[0x10-15];                      /* \97\\94õ                     */
2473         }NFD_DIAG_ID1,*LP_NFD_DIAG_ID1;
2474         
2475         // check nfd header
2476         NFD_FILE_HEAD1 head;
2477         
2478         fio->Fseek(0, FILEIO_SEEK_SET);
2479         fio->Fread(&head, sizeof(head), 1);
2480         
2481         if(strncmp(head.szFileID, "T98FDDIMAGE.R1", 14) != 0) {
2482                 return false;
2483         }
2484         fio->Fseek(head.dwHeadSize, FILEIO_SEEK_SET);
2485         
2486         // not implemented yet :-(
2487         return false;
2488 }
2489
2490 // solid image decoder
2491
2492 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2493 {
2494         int n = 0, t = 0;
2495         
2496         media_type = type;
2497         solid_ncyl = ncyl;
2498         solid_nside = nside;
2499         solid_nsec = nsec;
2500         solid_size = size;
2501         solid_mfm = mfm;
2502         
2503         // create d88 header
2504         d88_hdr_t d88_hdr;
2505         d88_sct_t d88_sct;
2506         
2507         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2508         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2509         d88_hdr.protect = 0; // non-protected
2510         
2511         file_size.d = 0;
2512         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2513         
2514         // sector length
2515         for(int i = 0; i < 8; i++) {
2516                 if(size == (128 << i)) {
2517                         n = i;
2518                         break;
2519                 }
2520         }
2521         
2522         // create tracks
2523         int trkptr = sizeof(d88_hdr_t);
2524         
2525         for(int c = 0; c < ncyl; c++) {
2526                 for(int h = 0; h < nside; h++) {
2527                         d88_hdr.trkptr[t++] = trkptr;
2528                         if(nside == 1) {
2529                                 t++;
2530                         }
2531                         
2532                         // read sectors in this track
2533                         for(int s = 0; s < nsec; s++) {
2534                                 // create d88 sector header
2535                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2536                                 d88_sct.c = c;
2537                                 d88_sct.h = h;
2538                                 d88_sct.r = s + 1;
2539                                 d88_sct.n = n;
2540                                 d88_sct.nsec = nsec;
2541                                 d88_sct.dens = 0;
2542                                 d88_sct.del = 0;
2543                                 d88_sct.stat = 0;
2544                                 d88_sct.size = size;
2545                                 
2546                                 // create sector image
2547                                 uint8_t dst[16384];
2548                                 memset(dst, 0xe5, sizeof(dst));
2549                                 fio->Fread(dst, size, 1);
2550                                 
2551                                 // copy to d88
2552                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2553                                 COPYBUFFER(dst, size);
2554                                 trkptr += sizeof(d88_sct_t) + size;
2555                         }
2556                 }
2557         }
2558         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2559         d88_hdr.size = trkptr;
2560         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2561         return true;
2562 }
2563
2564 #define STATE_VERSION   14
2565
2566 #include "../../statesub.h"
2567
2568 void DISK::decl_state()
2569 {
2570         state_entry = new csp_state_utils(STATE_VERSION, drive_num, _T("FLOPPY_DISK"));
2571
2572         DECL_STATE_ENTRY_1D_ARRAY(buffer, sizeof(buffer));
2573         DECL_STATE_ENTRY_STRING(orig_path, sizeof(orig_path) / sizeof(_TCHAR));
2574         DECL_STATE_ENTRY_STRING(dest_path, sizeof(dest_path) / sizeof(_TCHAR));
2575         
2576         DECL_STATE_ENTRY_PAIR(file_size);
2577         DECL_STATE_ENTRY_INT32(file_bank);
2578         DECL_STATE_ENTRY_UINT32(orig_file_size);
2579         DECL_STATE_ENTRY_UINT32(orig_crc32);
2580         DECL_STATE_ENTRY_BOOL(trim_required);
2581         DECL_STATE_ENTRY_BOOL(is_1dd_image);
2582         DECL_STATE_ENTRY_BOOL(is_solid_image);
2583         DECL_STATE_ENTRY_BOOL(is_fdi_image);
2584         
2585         DECL_STATE_ENTRY_1D_ARRAY(fdi_header, sizeof(fdi_header));
2586         
2587         DECL_STATE_ENTRY_INT32(solid_ncyl);
2588         DECL_STATE_ENTRY_INT32(solid_nside);
2589         DECL_STATE_ENTRY_INT32(solid_nsec);
2590         DECL_STATE_ENTRY_INT32(solid_size);
2591         DECL_STATE_ENTRY_BOOL(solid_mfm);
2592         DECL_STATE_ENTRY_BOOL(inserted);
2593         DECL_STATE_ENTRY_BOOL(ejected);
2594         DECL_STATE_ENTRY_BOOL(write_protected);
2595         DECL_STATE_ENTRY_BOOL(changed);
2596         DECL_STATE_ENTRY_UINT8(media_type);
2597         DECL_STATE_ENTRY_INT32(is_special_disk);
2598         
2599         DECL_STATE_ENTRY_1D_ARRAY(track, sizeof(track));
2600                                                           
2601         DECL_STATE_ENTRY_PAIR(sector_num);
2602         DECL_STATE_ENTRY_BOOL(track_mfm);
2603         DECL_STATE_ENTRY_BOOL(invalid_format);
2604 //      DECL_STATE_ENTRY_BOOL(no_skew);
2605         DECL_STATE_ENTRY_1D_ARRAY(sync_position, sizeof(sync_position) / sizeof(int));
2606         DECL_STATE_ENTRY_1D_ARRAY(am1_position, sizeof(am1_position) / sizeof(int));
2607         DECL_STATE_ENTRY_1D_ARRAY(id_position, sizeof(id_position) / sizeof(int));
2608         DECL_STATE_ENTRY_1D_ARRAY(data_position, sizeof(data_position) / sizeof(int));
2609 //      DECL_STATE_ENTRY_INT32(gap3_size);
2610         DECL_STATE_ENTRY_INT32(_tmp_sector_offset);
2611         DECL_STATE_ENTRY_PAIR(sector_size);
2612         
2613         DECL_STATE_ENTRY_1D_ARRAY(id, sizeof(id));
2614         DECL_STATE_ENTRY_UINT8(density);
2615         DECL_STATE_ENTRY_BOOL(deleted);
2616         DECL_STATE_ENTRY_BOOL(addr_crc_error);
2617         DECL_STATE_ENTRY_BOOL(data_crc_error);
2618         DECL_STATE_ENTRY_UINT8(drive_type);
2619         DECL_STATE_ENTRY_INT32(drive_rpm);
2620         DECL_STATE_ENTRY_BOOL(drive_mfm);
2621 }
2622 void DISK::save_state(FILEIO* state_fio)
2623 {
2624         _tmp_sector_offset = (sector != NULL) ? (int)(sector - buffer) : -1;
2625         
2626         if(state_entry != NULL) {
2627                 state_entry->save_state(state_fio);
2628         }
2629         //state_fio->FputUint32(STATE_VERSION);
2630         
2631         //state_fio->Fwrite(buffer, sizeof(buffer), 1);
2632         //state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2633         //state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2634         //state_fio->FputUint32(file_size.d);
2635         //state_fio->FputInt32(file_bank);
2636         //state_fio->FputUint32(orig_file_size);
2637         //state_fio->FputUint32(orig_crc32);
2638         //state_fio->FputBool(trim_required);
2639         //state_fio->FputBool(is_1dd_image);
2640         //state_fio->FputBool(is_solid_image);
2641         //state_fio->FputBool(is_fdi_image);
2642         //state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2643         //state_fio->FputInt32(solid_ncyl);
2644         //state_fio->FputInt32(solid_nside);
2645         //state_fio->FputInt32(solid_nsec);
2646         //state_fio->FputInt32(solid_size);
2647         //state_fio->FputBool(solid_mfm);
2648         //state_fio->FputBool(inserted);
2649         //state_fio->FputBool(ejected);
2650         //state_fio->FputBool(write_protected);
2651         //state_fio->FputBool(changed);
2652         //state_fio->FputUint8(media_type);
2653         //state_fio->FputInt32(is_special_disk);
2654         //state_fio->Fwrite(track, sizeof(track), 1);
2655         //state_fio->FputInt32(sector_num.sd);
2656         //state_fio->FputBool(track_mfm);
2657         //state_fio->FputBool(invalid_format);
2658 //      state_fio->FputBool(no_skew);
2659         //state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2660         //state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2661         //state_fio->Fwrite(id_position, sizeof(id_position), 1);
2662         //state_fio->Fwrite(data_position, sizeof(data_position), 1);
2663 //      state_fio->FputInt32(gap3_size);
2664         //state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2665         //state_fio->FputInt32(sector_size.sd);
2666         //state_fio->Fwrite(id, sizeof(id), 1);
2667         //state_fio->FputUint8(density);
2668         //state_fio->FputBool(deleted);
2669         //state_fio->FputBool(addr_crc_error);
2670         //state_fio->FputBool(data_crc_error);
2671         //state_fio->FputUint8(drive_type);
2672         //state_fio->FputInt32(drive_rpm);
2673         //state_fio->FputBool(drive_mfm);
2674 }
2675
2676 bool DISK::load_state(FILEIO* state_fio)
2677 {
2678         bool mb = false;
2679         if(state_entry != NULL) {
2680                 mb = state_entry->load_state(state_fio);
2681         }
2682         if(!mb) return false;
2683         //if(state_fio->FgetUint32() != STATE_VERSION) {
2684         //      return false;
2685         //}
2686         //state_fio->Fread(buffer, sizeof(buffer), 1);
2687         //state_fio->Fread(orig_path, sizeof(orig_path), 1);
2688         //state_fio->Fread(dest_path, sizeof(dest_path), 1);
2689         //file_size.d = state_fio->FgetUint32();
2690         //file_bank = state_fio->FgetInt32();
2691         //orig_file_size = state_fio->FgetUint32();
2692         //orig_crc32 = state_fio->FgetUint32();
2693         //trim_required = state_fio->FgetBool();
2694         //is_1dd_image = state_fio->FgetBool();
2695         //is_solid_image = state_fio->FgetBool();
2696         //is_fdi_image = state_fio->FgetBool();
2697         //state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2698         //solid_ncyl = state_fio->FgetInt32();
2699         //solid_nside = state_fio->FgetInt32();
2700         //solid_nsec = state_fio->FgetInt32();
2701         //solid_size = state_fio->FgetInt32();
2702         //solid_mfm = state_fio->FgetBool();
2703         //inserted = state_fio->FgetBool();
2704         //ejected = state_fio->FgetBool();
2705         //write_protected = state_fio->FgetBool();
2706         //changed = state_fio->FgetBool();
2707         //media_type = state_fio->FgetUint8();
2708         //is_special_disk = state_fio->FgetInt32();
2709         //state_fio->Fread(track, sizeof(track), 1);
2710         //sector_num.sd = state_fio->FgetInt32();
2711         //track_mfm = state_fio->FgetBool();
2712         //invalid_format = state_fio->FgetBool();
2713 //      no_skew = state_fio->FgetBool();
2714         //state_fio->Fread(sync_position, sizeof(sync_position), 1);
2715         //state_fio->Fread(am1_position, sizeof(am1_position), 1);
2716         //state_fio->Fread(id_position, sizeof(id_position), 1);
2717         //state_fio->Fread(data_position, sizeof(data_position), 1);
2718 //      gap3_size = state_fio->FgetInt32();
2719         //int offset = state_fio->FgetInt32();
2720         //sector = (offset != -1) ? buffer + offset : NULL;
2721         //sector_size.sd = state_fio->FgetInt32();
2722         //state_fio->Fread(id, sizeof(id), 1);
2723         //density = state_fio->FgetUint8();
2724         //deleted = state_fio->FgetBool();
2725         //addr_crc_error = state_fio->FgetBool();
2726         //data_crc_error = state_fio->FgetBool();
2727         //drive_type = state_fio->FgetUint8();
2728         //drive_rpm = state_fio->FgetInt32();
2729         //drive_mfm = state_fio->FgetBool();
2730         sector = (_tmp_sector_offset != -1) ? (buffer + _tmp_sector_offset) : NULL;
2731         return true;
2732 }
2733