OSDN Git Service

[VM][PC9801][MEMBUS] Split update_bios() to functions.
[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                                 pair32_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                                 pair32_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                                         pair32_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                                         pair32_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                                 pair32_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                                 pair32_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                                 pair32_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                                         pair32_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                                         pair32_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                                                 pair32_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                                                 pair32_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) {
922                         if(trk & 1) {
923                                 return false; // unformat
924                         }
925                         trk >>= 1;
926                 }
927         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
928                 if(trk >= 0) trk <<= 1;
929         }
930         return get_track_tmp(trk, side);
931 }
932
933 bool DISK::get_track_tmp(int trk, int side)
934 {
935         sector_size.sd = sector_num.sd = 0;
936         invalid_format = false;
937 //      no_skew = true;
938         
939         // disk not inserted or invalid media type
940         if(!(inserted && check_media_type())) {
941                 return false;
942         }
943         
944         // search track
945         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
946         if(!(0 <= trkside && trkside < 164)) {
947                 return false;
948         }
949         cur_track = trk;
950         cur_side = side;
951         
952         pair32_t offset;
953         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
954         
955         if(!IS_VALID_TRACK(offset.d)) {
956                 return false;
957         }
958         
959         // track found
960         sector = buffer + offset.d;
961         sector_num.read_2bytes_le_from(sector + 4);
962         pair32_t data_size;
963         data_size.read_2bytes_le_from(sector + 14);
964         
965         // create each sector position in track
966         track_mfm = false;
967         if(sector_num.sd == 0) {
968                 track_mfm = drive_mfm;
969         } else {
970                 uint8_t* t = sector;
971                 for(int i = 0; i < sector_num.sd; i++) {
972                         data_size.read_2bytes_le_from(t + 14);
973                         // t[6]: 0x00 = double-density, 0x40 = single-density
974                         if(t[6] == 0x00) {
975                                 track_mfm = true;
976                                 break;
977                         }
978                         t += data_size.sd + 0x10;
979                 }
980         }
981         int sync_size  = track_mfm ? 12 : 6;
982         int am_size = track_mfm ? 3 : 0;
983         int gap0_size = track_mfm ? 80 : 40;
984         int gap1_size = track_mfm ? 50 : 26;
985         int gap2_size = track_mfm ? 22 : 11;
986         int gap3_size = 0, gap4_size;
987         
988         if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
989                 if(track_mfm) {
990                         if(data_size.sd ==  256 && sector_num.sd == 26) gap3_size =  54;
991                         if(data_size.sd ==  512 && sector_num.sd == 15) gap3_size =  84;
992                         if(data_size.sd == 1024 && sector_num.sd ==  8) gap3_size = 116;
993                 } else {
994                         if(data_size.sd ==  128 && sector_num.sd == 26) gap3_size =  27;
995                         if(data_size.sd ==  256 && sector_num.sd == 15) gap3_size =  42;
996                         if(data_size.sd ==  512 && sector_num.sd ==  8) gap3_size =  58;
997                 }
998         } else {
999                 if(track_mfm) {
1000                         if(data_size.sd ==  256 && sector_num.sd == 16) gap3_size =  51;
1001                         if(data_size.sd ==  512 && sector_num.sd ==  9) gap3_size =  80;
1002                         if(data_size.sd == 1024 && sector_num.sd ==  5) gap3_size = 116;
1003                 } else {
1004                         if(data_size.sd ==  128 && sector_num.sd == 16) gap3_size =  27;
1005                         if(data_size.sd ==  256 && sector_num.sd ==  9) gap3_size =  42;
1006                         if(data_size.sd ==  512 && sector_num.sd ==  5) gap3_size =  58;
1007                 }
1008         }
1009         
1010         uint8_t* t = sector;
1011         int total = 0, valid_sector_num = 0;
1012         
1013         for(int i = 0; i < sector_num.sd; i++) {
1014                 data_size.read_2bytes_le_from(t + 14);
1015                 sync_position[i] = total; // for invalid format case
1016                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
1017                 if(data_size.sd > 0) {
1018                         total += sync_size + (am_size + 1);
1019                         total += data_size.sd + 2;
1020                         valid_sector_num++;
1021                 }
1022 //              if(t[2] != i + 1) {
1023 //                      no_skew = false;
1024 //              }
1025                 t += data_size.sd + 0x10;
1026         }
1027         total += sync_size + (am_size + 1); // sync in preamble
1028         
1029         if(gap3_size == 0) {
1030                 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
1031         }
1032         gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
1033         
1034         if(gap3_size < 8 || gap4_size < 8) {
1035                 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
1036                 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
1037         }
1038         if(gap3_size < 8 || gap4_size < 8) {
1039                 gap0_size = gap1_size = gap3_size = gap4_size = 8;
1040                 invalid_format = true;
1041         }
1042         int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
1043         
1044         if(invalid_format) {
1045                 total -= sync_size + (am_size + 1);
1046                 for(int i = 0; i < sector_num.sd; i++) {
1047                         sync_position[i] *= get_track_size() - preamble_size - gap4_size;
1048                         sync_position[i] /= total;
1049                 }
1050         }
1051         t = sector;
1052         total = preamble_size;
1053         sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
1054         
1055         for(int i = 0; i < sector_num.sd; i++) {
1056                 data_size.read_2bytes_le_from(t + 14);
1057                 if(invalid_format) {
1058                         total = preamble_size + sync_position[i];
1059                 }
1060                 sync_position[i] = total;
1061                 total += sync_size;
1062                 am1_position[i] = total;
1063                 total += am_size + 1;
1064                 id_position[i] = total;
1065                 total += (4 + 2) + gap2_size;
1066                 if(data_size.sd > 0) {
1067                         total += sync_size + (am_size + 1);
1068                         data_position[i] = total;
1069                         total += data_size.sd + 2;
1070                         total += gap3_size;
1071                 } else {
1072                         data_position[i] = total; // FIXME
1073                 }
1074                 t += data_size.sd + 0x10;
1075         }
1076         return true;
1077 }
1078
1079 bool DISK::make_track(int trk, int side)
1080 {
1081         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1082                 if(trk >= 0) {
1083                         if(trk & 1) {
1084                                 return false; // unformat
1085                         }
1086                         trk >>= 1;
1087                 }
1088         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1089                 if(trk >= 0) trk <<= 1;
1090         }
1091         return make_track_tmp(trk, side);
1092 }
1093
1094 bool DISK::make_track_tmp(int trk, int side)
1095 {
1096         int track_size = get_track_size();
1097         
1098         if(!get_track_tmp(trk, side)) {
1099                 // create a dummy track
1100                 for(int i = 0; i < track_size; i++) {
1101                         track[i] = rand();
1102                 }
1103                 return false;
1104         }
1105         
1106         // make track image
1107         int sync_size  = track_mfm ? 12 : 6;
1108         int am_size = track_mfm ? 3 : 0;
1109         int gap2_size = track_mfm ? 22 : 11;
1110         uint8_t gap_data = track_mfm ? 0x4e : 0xff;
1111         
1112         // preamble
1113         memset(track, gap_data, track_size);
1114         int q = sync_position[array_length(sync_position) - 1];
1115         
1116         // sync
1117         for(int i = 0; i < sync_size; i++) {
1118                 track[q++] = 0x00;
1119         }
1120         // index mark
1121         for(int i = 0; i < am_size; i++) {
1122                 track[q++] = 0xc2;
1123         }
1124         track[q++] = 0xfc;
1125         
1126         // sectors
1127         uint8_t *t = sector;
1128         
1129         for(int i = 0; i < sector_num.sd; i++) {
1130                 pair32_t data_size;
1131                 data_size.read_2bytes_le_from(t + 14);
1132                 int p = sync_position[i];
1133                 
1134                 // sync
1135                 for(int j = 0; j < sync_size; j++) {
1136                         if(p < track_size) track[p++] = 0x00;
1137                 }
1138                 // am1
1139                 uint16_t crc = 0xffff;
1140                 for(int j = 0; j < am_size; j++) {
1141                         if(p < track_size) track[p++] = 0xa1;
1142                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1143                 }
1144                 if(p < track_size) track[p++] = 0xfe;
1145                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1146                 // id
1147                 if(p < track_size) track[p++] = t[0];
1148                 if(p < track_size) track[p++] = t[1];
1149                 if(p < track_size) track[p++] = t[2];
1150                 if(p < track_size) track[p++] = t[3];
1151                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1152                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1153                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1154                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1155                 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1156                 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1157                 // gap2
1158                 for(int j = 0; j < gap2_size; j++) {
1159                         if(p < track_size) track[p++] = gap_data;
1160                 }
1161                 // data field
1162                 if(data_size.sd > 0) {
1163                         // sync
1164                         for(int j = 0; j < sync_size; j++) {
1165                                 if(p < track_size) track[p++] = 0x00;
1166                         }
1167                         // am2
1168                         crc = 0xffff;
1169                         for(int j = 0; j < am_size; j++) {
1170                                 if(p < track_size) track[p++] = 0xa1;
1171                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1172                         }
1173                         uint8_t am2 = (t[7] != 0) ? 0xf8 : 0xfb;
1174                         if(p < track_size) track[p++] = am2;
1175                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ am2]);
1176                         // data
1177                         for(int j = 0; j < data_size.sd; j++) {
1178                                 if(p < track_size) track[p++] = t[0x10 + j];
1179                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
1180                         }
1181                         if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1182                         if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1183                 }
1184                 t += data_size.sd + 0x10;
1185         }
1186         return true;
1187 }
1188
1189 bool DISK::get_sector(int trk, int side, int index)
1190 {
1191         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1192                 if(trk >= 0) {
1193                         if(trk & 1) {
1194                                 return false; // unformat
1195                         }
1196                         trk >>= 1;
1197                 }
1198         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1199                 if(trk >= 0) trk <<= 1;
1200         }
1201         return get_sector_tmp(trk, side, index);
1202 }
1203
1204 bool DISK::get_sector_tmp(int trk, int side, int index)
1205 {
1206         sector_size.sd = sector_num.sd = 0;
1207         sector = NULL;
1208         
1209         // disk not inserted or invalid media type
1210         if(!(inserted && check_media_type())) {
1211                 return false;
1212         }
1213         
1214         // search track
1215         if(trk == -1 && side == -1) {
1216                 trk = cur_track;
1217                 side = cur_side;
1218         }
1219         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1220         if(!(0 <= trkside && trkside < 164)) {
1221                 return false;
1222         }
1223         pair32_t offset;
1224         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1225         
1226         if(!IS_VALID_TRACK(offset.d)) {
1227                 return false;
1228         }
1229         
1230         // track found
1231         uint8_t* t = buffer + offset.d;
1232         sector_num.read_2bytes_le_from(t + 4);
1233         
1234         if(index >= sector_num.sd) {
1235                 return false;
1236         }
1237         
1238         // skip sector
1239         for(int i = 0; i < index; i++) {
1240                 pair32_t data_size;
1241                 data_size.read_2bytes_le_from(t + 14);
1242                 t += data_size.sd + 0x10;
1243         }
1244         set_sector_info(t);
1245         return true;
1246 }
1247
1248 void DISK::set_sector_info(uint8_t *t)
1249 {
1250         // header info
1251         int am_size = track_mfm ? 3 : 0;
1252         uint16_t crc = 0xffff;
1253         for(int i = 0; i < am_size; i++) {
1254                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1255         }
1256         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1257         id[0] = t[0];
1258         id[1] = t[1];
1259         id[2] = t[2];
1260         id[3] = t[3];
1261         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1262         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1263         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1264         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1265         id[4] = (crc >> 8) & 0xff;
1266         id[5] = (crc >> 0) & 0xff;
1267         //id[4] = t[4];
1268         //id[5] = t[5];
1269         // http://www.gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1270         // t[6]: 0x00 = double-density, 0x40 = single-density
1271         // t[7]: 0x00 = normal, 0x10 = deleted mark
1272         // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1273         density = t[6];
1274         deleted = (t[7] != 0);
1275 //      if(ignore_crc()) {
1276 //              addr_crc_error = false;
1277 //              data_crc_error = false;
1278 //      } else {
1279                 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1280                 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1281 //      }
1282         if(addr_crc_error || data_crc_error) {
1283                 id[4] = t[4];
1284                 id[5] = t[5];
1285         }
1286         sector = t + 0x10;
1287         sector_size.read_2bytes_le_from(t + 14);
1288 }
1289
1290 bool DISK::get_sector_info(int trk, int side, int index, uint8_t *c, uint8_t *h, uint8_t *r, uint8_t *n, int *length)
1291 {
1292         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1293                 if(trk >= 0) {
1294                         if(trk & 1) {
1295                                 return false; // unformat
1296                         }
1297                         trk >>= 1;
1298                 }
1299         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1300                 if(trk >= 0) trk <<= 1;
1301         }
1302         return get_sector_info_tmp(trk, side, index, c, h, r, n, length);
1303 }
1304
1305 bool DISK::get_sector_info_tmp(int trk, int side, int index, uint8_t *c, uint8_t *h, uint8_t *r, uint8_t *n, int *length)
1306 {
1307         // search track
1308         if(trk == -1 && side == -1) {
1309                 trk = cur_track;
1310                 side = cur_side;
1311         }
1312         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1313         if(!(0 <= trkside && trkside < 164)) {
1314                 return false;
1315         }
1316         pair32_t offset;
1317         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1318         
1319         if(!IS_VALID_TRACK(offset.d)) {
1320                 return false;
1321         }
1322         
1323         // track found
1324         uint8_t* t = buffer + offset.d;
1325         pair32_t num, data_size;
1326         num.read_2bytes_le_from(t + 4);
1327         
1328         if(index >= num.sd) {
1329                 return false;
1330         }
1331         
1332         // skip sector
1333         for(int i = 0; i < index; i++) {
1334                 data_size.read_2bytes_le_from(t + 14);
1335                 t += data_size.sd + 0x10;
1336         }
1337         data_size.read_2bytes_le_from(t + 14);
1338         *c = t[0];
1339         *h = t[1];
1340         *r = t[2];
1341         *n = t[3];
1342         *length = data_size.sd;
1343         return true;
1344 }
1345
1346 void DISK::set_deleted(bool value)
1347 {
1348         if(sector != NULL) {
1349                 uint8_t *t = sector - 0x10;
1350                 t[7] = value ? 0x10 : 0;
1351                 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1352                         t[8] = (t[8] & 0x0f) | t[7];
1353                 }
1354         }
1355         deleted = value;
1356 }
1357
1358 void DISK::set_data_crc_error(bool value)
1359 {
1360         if(sector != NULL) {
1361                 uint8_t *t = sector - 0x10;
1362                 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1363         }
1364         data_crc_error = value;
1365 }
1366
1367 void DISK::set_data_mark_missing()
1368 {
1369         if(sector != NULL) {
1370                 uint8_t *t = sector - 0x10;
1371                 t[8] = (t[8] & 0x0f) | 0xf0;
1372                 t[14] = t[15] = 0;
1373         }
1374 //      addr_crc_error = false;
1375         data_crc_error = false;
1376 }
1377
1378 bool DISK::format_track(int trk, int side)
1379 {
1380         if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) {
1381                 if(trk >= 0) {
1382                         if(trk & 1) {
1383                                 return false; // unformat
1384                         }
1385                         trk >>= 1;
1386                 }
1387         } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) {
1388                 if(trk >= 0) trk <<= 1;
1389         }
1390         return format_track_tmp(trk, side);
1391 }
1392
1393 bool DISK::format_track_tmp(int trk, int side)
1394 {
1395         // disk not inserted or invalid media type
1396         if(!(inserted && check_media_type())) {
1397                 return false;
1398         }
1399         
1400         // search track
1401         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1402         if(!(0 <= trkside && trkside < 164)) {
1403                 return false;
1404         }
1405         
1406         // create new empty track
1407         if(trim_required) {
1408                 trim_buffer();
1409                 trim_required = false;
1410         }
1411         memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1412         pair32_t offset;
1413         offset.d = DISK_BUFFER_SIZE;
1414         offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1415         
1416         trim_required = true;
1417         sector_num.sd = 0;
1418         track_mfm = drive_mfm;
1419         
1420         return true;
1421 }
1422
1423 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)
1424 {
1425         uint8_t* t = buffer + DISK_BUFFER_SIZE;
1426         
1427         sector_num.sd++;
1428         for(int i = 0; i < (sector_num.sd - 1); i++) {
1429                 t[4] = sector_num.b.l;
1430                 t[5] = sector_num.b.h;
1431                 pair32_t data_size;
1432                 data_size.read_2bytes_le_from(t + 14);
1433                 t += data_size.sd + 0x10;
1434         }
1435         t[0] = c;
1436         t[1] = h;
1437         t[2] = r;
1438         t[3] = n;
1439         t[4] = sector_num.b.l;
1440         t[5] = sector_num.b.h;
1441         t[6] = track_mfm ? 0 : 0x40;
1442         t[7] = deleted ? 0x10 : 0;
1443         t[8] = data_crc_error ? 0xb0 : t[7];
1444         t[14] = (length >> 0) & 0xff;
1445         t[15] = (length >> 8) & 0xff;
1446         memset(t + 16, fill_data, length);
1447         
1448         set_sector_info(t);
1449 }
1450
1451 void DISK::sync_buffer()
1452 {
1453         if(trim_required) {
1454                 trim_buffer();
1455                 trim_required = false;
1456         }
1457 }
1458
1459 void DISK::trim_buffer()
1460 {
1461         int max_tracks = 164;
1462         int track_limit = 164;
1463         uint32_t dest_offset = 0x2b0;
1464         
1465         // copy header
1466         memset(tmp_buffer, 0, sizeof(tmp_buffer));
1467         memcpy(tmp_buffer, buffer, 0x20);
1468         
1469         // check max tracks
1470         if(media_type == MEDIA_TYPE_2D) {
1471                 track_limit = 84;
1472         }
1473         for(int trkside = 0; trkside < 164; trkside++) {
1474                 pair32_t src_trk_offset;
1475                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1476                 if(src_trk_offset.d != 0) {
1477 #if 1
1478                         if(src_trk_offset.d < 0x2b0) {
1479                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1480                                 if(max_tracks > track_limit) {
1481                                         max_tracks = track_limit;
1482                                 }
1483                         }
1484 #else
1485                         if(src_trk_offset.d != 0x2b0) {
1486                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1487                                 if(max_tracks > 164) {
1488                                         dest_offset = 0x20 + max_tracks * 4);
1489                                 }
1490                         }
1491 #endif
1492                         break;
1493                 }
1494         }
1495         
1496         // copy tracks
1497         for(int trkside = 0; trkside < max_tracks; trkside++) {
1498                 pair32_t src_trk_offset;
1499                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1500                 
1501                 pair32_t dest_trk_offset;
1502                 dest_trk_offset.d = 0;
1503                 
1504                 if(IS_VALID_TRACK(src_trk_offset.d)) {
1505                         uint8_t* t = buffer + src_trk_offset.d;
1506                         pair32_t sector_num, data_size;
1507                         sector_num.read_2bytes_le_from(t + 4);
1508                         if(sector_num.sd != 0) {
1509                                 dest_trk_offset.d = dest_offset;
1510                                 for(int i = 0; i < sector_num.sd; i++) {
1511                                         data_size.read_2bytes_le_from(t + 14);
1512                                         memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1513                                         dest_offset += data_size.sd + 0x10;
1514                                         t += data_size.sd + 0x10;
1515                                 }
1516                         }
1517                 }
1518                 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1519         }
1520         
1521         // update file size
1522         file_size.d = dest_offset;
1523         file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1524         
1525         memset(buffer, 0, sizeof(buffer));
1526         memcpy(buffer, tmp_buffer, min((unsigned int)sizeof(buffer), file_size.d));
1527 }
1528
1529 int DISK::get_max_tracks()
1530 {
1531         if(drive_type != DRIVE_TYPE_UNK) {
1532                 return (drive_type != DRIVE_TYPE_2D) ? 84 : 42;
1533         } else if(inserted) {
1534                 return (media_type != MEDIA_TYPE_2D) ? 84 : 42;
1535         } else {
1536                 return 84; // 2DD or 2HD
1537         }
1538 }
1539
1540 int DISK::get_rpm()
1541 {
1542         if(drive_rpm != 0) {
1543                 return drive_rpm;
1544         } else if(inserted) {
1545                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1546         } else {
1547                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1548         }
1549 }
1550
1551 int DISK::get_track_size()
1552 {
1553         if(track_size != 0) {
1554                 return track_size;
1555         } else if(inserted) {
1556                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1557         } else {
1558                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1559         }
1560 }
1561
1562 double DISK::get_usec_per_track()
1563 {
1564         return 1000000.0 / (get_rpm() / 60.0);
1565 }
1566
1567 double DISK::get_usec_per_bytes(int bytes)
1568 {
1569         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1570 }
1571
1572 int DISK::get_bytes_per_usec(double usec)
1573 {
1574         return (int)(usec / get_usec_per_bytes(1) + 0.5);
1575 }
1576
1577 bool DISK::check_media_type()
1578 {
1579         switch(drive_type) {
1580         case DRIVE_TYPE_2D:
1581                         return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1582         case DRIVE_TYPE_2DD:
1583                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1584         case DRIVE_TYPE_2HD:
1585                 return (media_type == MEDIA_TYPE_2HD);
1586         case DRIVE_TYPE_144:
1587                 return (media_type == MEDIA_TYPE_144);
1588         case DRIVE_TYPE_UNK:
1589                 return true; // always okay
1590         }
1591         return false;
1592 }
1593
1594 // image decoder
1595
1596 #define COPYBUFFER(src, size) { \
1597         if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1598                 return false; \
1599         } \
1600         memcpy(buffer + file_size.d, (src), (size)); \
1601         file_size.d += (size); \
1602 }
1603
1604 typedef struct {
1605         char title[17];
1606         uint8_t rsrv[9];
1607         uint8_t protect;
1608         uint8_t type;
1609         uint32_t size;
1610         uint32_t trkptr[164];
1611 } d88_hdr_t;
1612
1613 typedef struct {
1614         uint8_t c, h, r, n;
1615         uint16_t nsec;
1616         uint8_t dens, del, stat;
1617         uint8_t rsrv[5];
1618         uint16_t size;
1619 } d88_sct_t;
1620
1621 // teledisk image decoder
1622
1623 /*
1624         this teledisk image decoder is based on:
1625         
1626                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1627                 LZSS coded by Haruhiko OKUMURA
1628                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1629                 Edited and translated to English by Kenji RIKITAKE
1630                 TDLZHUF.C by WTK
1631 */
1632
1633 #define STRING_BUFFER_SIZE      4096
1634 #define LOOKAHEAD_BUFFER_SIZE   60
1635 #define THRESHOLD               2
1636 #define N_CHAR                  (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1637 #define TABLE_SIZE              (N_CHAR * 2 - 1)
1638 #define ROOT_POSITION           (TABLE_SIZE - 1)
1639 #define MAX_FREQ                0x8000
1640
1641 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1642 static uint16_t td_ptr;
1643 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1644 static uint16_t td_ibufcnt, td_ibufndx;
1645 static uint8_t td_inbuf[512];
1646 static uint16_t td_freq[TABLE_SIZE + 1];
1647 static short td_prnt[TABLE_SIZE + N_CHAR];
1648 static short td_son[TABLE_SIZE];
1649 static uint16_t td_getbuf;
1650 static uint8_t td_getlen;
1651
1652 static const uint8_t td_d_code[256] = {
1653         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1654         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1655         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1656         0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1657         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1658         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1659         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1660         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1661         0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1662         0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1663         0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1664         0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1665         0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1666         0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1667         0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1668         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1669 };
1670 static const uint8_t td_d_len[256] = {
1671         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1672         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1673         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1674         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1675         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1676         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1677         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1678         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1679         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1680         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1681         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1682         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1683         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1684         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1685         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1686         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1687 };
1688
1689 static int td_next_word(FILEIO* fio)
1690 {
1691         if(td_ibufndx >= td_ibufcnt) {
1692                 td_ibufndx = td_ibufcnt = 0;
1693                 memset(td_inbuf, 0, 512);
1694                 for(int i = 0; i < 512; i++) {
1695                         int d = fio->Fgetc();
1696                         if(d == EOF) {
1697                                 if(i) {
1698                                         break;
1699                                 }
1700                                 return(-1);
1701                         }
1702                         td_inbuf[i] = d;
1703                         td_ibufcnt = i + 1;
1704                 }
1705         }
1706         while(td_getlen <= 8) {
1707                 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1708                 td_getlen += 8;
1709         }
1710         return 0;
1711 }
1712
1713 static int td_get_bit(FILEIO* fio)
1714 {
1715         if(td_next_word(fio) < 0) {
1716                 return -1;
1717         }
1718         short i = td_getbuf;
1719         td_getbuf <<= 1;
1720         td_getlen--;
1721         return (i < 0) ? 1 : 0;
1722 }
1723
1724 static int td_get_byte(FILEIO* fio)
1725 {
1726         if(td_next_word(fio) != 0) {
1727                 return -1;
1728         }
1729         uint16_t i = td_getbuf;
1730         td_getbuf <<= 8;
1731         td_getlen -= 8;
1732         i >>= 8;
1733         return (int)i;
1734 }
1735
1736 static void td_start_huff()
1737 {
1738         int i, j;
1739         for(i = 0; i < N_CHAR; i++) {
1740                 td_freq[i] = 1;
1741                 td_son[i] = i + TABLE_SIZE;
1742                 td_prnt[i + TABLE_SIZE] = i;
1743         }
1744         i = 0; j = N_CHAR;
1745         while(j <= ROOT_POSITION) {
1746                 td_freq[j] = td_freq[i] + td_freq[i + 1];
1747                 td_son[j] = i;
1748                 td_prnt[i] = td_prnt[i + 1] = j;
1749                 i += 2; j++;
1750         }
1751         td_freq[TABLE_SIZE] = 0xffff;
1752         td_prnt[ROOT_POSITION] = 0;
1753 }
1754
1755 static void td_reconst()
1756 {
1757         short i, j = 0, k;
1758         uint16_t f, l;
1759         for(i = 0; i < TABLE_SIZE; i++) {
1760                 if(td_son[i] >= TABLE_SIZE) {
1761                         td_freq[j] = (td_freq[i] + 1) / 2;
1762                         td_son[j] = td_son[i];
1763                         j++;
1764                 }
1765         }
1766         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1767                 k = i + 1;
1768                 f = td_freq[j] = td_freq[i] + td_freq[k];
1769                 for(k = j - 1; f < td_freq[k]; k--);
1770                 k++;
1771                 l = (j - k) * 2;
1772                 memmove(&td_freq[k + 1], &td_freq[k], l);
1773                 td_freq[k] = f;
1774                 memmove(&td_son[k + 1], &td_son[k], l);
1775                 td_son[k] = i;
1776         }
1777         for(i = 0; i < TABLE_SIZE; i++) {
1778                 if((k = td_son[i]) >= TABLE_SIZE) {
1779                         td_prnt[k] = i;
1780                 } else {
1781                         td_prnt[k] = td_prnt[k + 1] = i;
1782                 }
1783         }
1784 }
1785
1786 static void td_update(int c)
1787 {
1788         int i, j, k, l;
1789         if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1790                 td_reconst();
1791         }
1792         c = td_prnt[c + TABLE_SIZE];
1793         do {
1794                 k = ++td_freq[c];
1795                 if(k > td_freq[l = c + 1]) {
1796                         while(k > td_freq[++l]);
1797                         l--;
1798                         td_freq[c] = td_freq[l];
1799                         td_freq[l] = k;
1800                         i = td_son[c];
1801                         td_prnt[i] = l;
1802                         if(i < TABLE_SIZE) {
1803                                 td_prnt[i + 1] = l;
1804                         }
1805                         j = td_son[l];
1806                         td_son[l] = i;
1807                         td_prnt[j] = c;
1808                         if(j < TABLE_SIZE) {
1809                                 td_prnt[j + 1] = c;
1810                         }
1811                         td_son[c] = j;
1812                         c = l;
1813                 }
1814         }
1815         while((c = td_prnt[c]) != 0);
1816 }
1817
1818 static short td_decode_char(FILEIO* fio)
1819 {
1820         int ret;
1821         uint16_t c = td_son[ROOT_POSITION];
1822         while(c < TABLE_SIZE) {
1823                 if((ret = td_get_bit(fio)) < 0) {
1824                         return -1;
1825                 }
1826                 c += (unsigned)ret;
1827                 c = td_son[c];
1828         }
1829         c -= TABLE_SIZE;
1830         td_update(c);
1831         return c;
1832 }
1833
1834 static short td_decode_position(FILEIO* fio)
1835 {
1836         short bit;
1837         uint16_t i, j, c;
1838         if((bit = td_get_byte(fio)) < 0) {
1839                 return -1;
1840         }
1841         i = (uint16_t)bit;
1842         c = (uint16_t)td_d_code[i] << 6;
1843         j = td_d_len[i] - 2;
1844         while(j--) {
1845                 if((bit = td_get_bit(fio)) < 0) {
1846                          return -1;
1847                 }
1848                 i = (i << 1) + bit;
1849         }
1850         return (c | (i & 0x3f));
1851 }
1852
1853 static void td_init_decode()
1854 {
1855         td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1856         td_getlen = 0;
1857         td_start_huff();
1858         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1859                 td_text_buf[i] = ' ';
1860         }
1861         td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1862 }
1863
1864 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1865 {
1866         short c, pos;
1867         int  count;
1868         for(count = 0; count < len;) {
1869                 if(td_bufcnt == 0) {
1870                         if((c = td_decode_char(fio)) < 0) {
1871                                 return count;
1872                         }
1873                         if(c < 256) {
1874                                 *(buf++) = (uint8_t)c;
1875                                 td_text_buf[td_ptr++] = (uint8_t)c;
1876                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1877                                 count++;
1878                         } else {
1879                                 if((pos = td_decode_position(fio)) < 0) {
1880                                         return count;
1881                                 }
1882                                 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1883                                 td_bufcnt = c - 255 + THRESHOLD;
1884                                 td_bufndx = 0;
1885                         }
1886                 } else {
1887                         while(td_bufndx < td_bufcnt && count < len) {
1888                                 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1889                                 *(buf++) = (uint8_t)c;
1890                                 td_bufndx++;
1891                                 td_text_buf[td_ptr++] = (uint8_t)c;
1892                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1893                                 count++;
1894                         }
1895                         if(td_bufndx >= td_bufcnt) {
1896                                 td_bufndx = td_bufcnt = 0;
1897                         }
1898                 }
1899         }
1900         return count;
1901 }
1902
1903 typedef struct {
1904         char sig[3];
1905         uint8_t unknown;
1906         uint8_t ver;
1907         uint8_t dens;
1908         uint8_t type;
1909         uint8_t flag;
1910         uint8_t dos;
1911         uint8_t sides;
1912         uint16_t crc;
1913 } td_hdr_t;
1914
1915 typedef struct {
1916         uint16_t crc;
1917         uint16_t len;
1918         uint8_t ymd[3];
1919         uint8_t hms[3];
1920 } td_cmt_t;
1921
1922 typedef struct {
1923         uint8_t nsec, trk, head;
1924         uint8_t crc;
1925 } td_trk_t;
1926
1927 typedef struct {
1928         uint8_t c, h, r, n;
1929         uint8_t ctrl, crc;
1930 } td_sct_t;
1931
1932 bool DISK::teledisk_to_d88(FILEIO *fio)
1933 {
1934         td_hdr_t hdr;
1935         td_cmt_t cmt;
1936         td_trk_t trk;
1937         td_sct_t sct;
1938         uint8_t obuf[512];
1939         bool temporary = false;
1940         
1941         // check teledisk header
1942         fio->Fseek(0, FILEIO_SEEK_SET);
1943         fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1944         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1945                 // this image is compressed
1946                 // decompress to the temporary file
1947                 FILEIO* fio_tmp = new FILEIO();
1948                 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1949                         delete fio_tmp;
1950                         return false;
1951                 }
1952                 int rd = 1;
1953                 td_init_decode();
1954                 do {
1955                         if((rd = td_decode(fio, obuf, 512)) > 0) {
1956                                 fio_tmp->Fwrite(obuf, rd, 1);
1957                         }
1958                 }
1959                 while(rd > 0);
1960                 fio_tmp->Fclose();
1961                 delete fio_tmp;
1962                 temporary = true;
1963                 
1964                 // reopen the temporary file
1965                 fio->Fclose();
1966                 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1967                         return false;
1968                 }
1969         } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1970                 // this image is not compressed
1971         } else {
1972                 return false;
1973         }
1974         if(hdr.flag & 0x80) {
1975                 // skip comment
1976                 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1977                 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1978         }
1979         
1980         // create d88 header
1981         d88_hdr_t d88_hdr;
1982         d88_sct_t d88_sct;
1983         
1984         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1985         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1986         d88_hdr.protect = 0; // non-protected
1987         
1988         file_size.d = 0;
1989         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1990         
1991         // create tracks
1992         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1993         fio->Fread(&trk, sizeof(td_trk_t), 1);
1994         while(trk.nsec != 0xff) {
1995                 d88_hdr.trkptr[trkcnt++] = trkptr;
1996                 if(hdr.sides == 1) {
1997                         trkcnt++;
1998                 }
1999                 
2000                 // read sectors in this track
2001                 for(int i = 0; i < trk.nsec; i++) {
2002                         uint8_t buf[2048], dst[2048];
2003                         memset(buf, 0, sizeof(buf));
2004                         memset(dst, 0, sizeof(dst));
2005                         
2006                         // read sector header
2007                         fio->Fread(&sct, sizeof(td_sct_t), 1);
2008                         
2009                         // create d88 sector header
2010                         memset(&d88_sct, 0, sizeof(d88_sct_t));
2011                         d88_sct.c = sct.c;
2012                         d88_sct.h = sct.h;
2013                         d88_sct.r = sct.r;
2014                         d88_sct.n = sct.n;
2015                         d88_sct.nsec = trk.nsec;
2016                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
2017                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
2018                         d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
2019                         d88_sct.size = secsize[sct.n & 3];
2020                         
2021                         // create sector image
2022                         if(sct.ctrl & 0x30) {
2023                                 d88_sct.stat = 0xf0; // data mark missing
2024                                 d88_sct.size = 0;
2025                         } else {
2026                                 // read sector source
2027                                 int len = fio->Fgetc();
2028                                 len += fio->Fgetc() * 256 - 1;
2029                                 int flag = fio->Fgetc(), d = 0;
2030                                 fio->Fread(buf, len, 1);
2031                                 
2032                                 // convert
2033                                 if(flag == 0) {
2034                                         memcpy(dst, buf, len);
2035                                 } else if(flag == 1) {
2036                                         pair32_t len2;
2037                                         len2.read_2bytes_le_from(buf);
2038                                         while(len2.sd--) {
2039                                                 dst[d++] = buf[2];
2040                                                 dst[d++] = buf[3];
2041                                         }
2042                                 } else if(flag == 2) {
2043                                         for(int s = 0; s < len;) {
2044                                                 int type = buf[s++];
2045                                                 int len2 = buf[s++];
2046                                                 if(type == 0) {
2047                                                         while(len2--) {
2048                                                                 dst[d++] = buf[s++];
2049                                                         }
2050                                                 } else if(type < 5) {
2051                                                         uint8_t pat[256];
2052                                                         int n = 2;
2053                                                         while(type-- > 1) {
2054                                                                 n *= 2;
2055                                                         }
2056                                                         for(int j = 0; j < n; j++) {
2057                                                                 pat[j] = buf[s++];
2058                                                         }
2059                                                         while(len2--) {
2060                                                                 for(int j = 0; j < n; j++) {
2061                                                                         dst[d++] = pat[j];
2062                                                                 }
2063                                                         }
2064                                                 } else {
2065                                                         break; // unknown type
2066                                                 }
2067                                         }
2068                                 } else {
2069                                         break; // unknown flag
2070                                 }
2071                         }
2072                         
2073                         // copy to d88
2074                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2075                         COPYBUFFER(dst, d88_sct.size);
2076                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2077                 }
2078                 // read next track
2079                 fio->Fread(&trk, sizeof(td_trk_t), 1);
2080         }
2081         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
2082         d88_hdr.size = trkptr;
2083         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2084         
2085         if(temporary) {
2086                 FILEIO::RemoveFile(_T("teledisk.$$$"));
2087         }
2088         return true;
2089 }
2090
2091 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
2092
2093 bool DISK::imagedisk_to_d88(FILEIO *fio)
2094 {
2095         int size = fio->FileLength();
2096         fio->Fseek(0, FILEIO_SEEK_SET);
2097         fio->Fread(tmp_buffer, size, 1);
2098         
2099         if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
2100                 return false;
2101         }
2102         
2103         int pos;
2104         for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
2105         pos++;
2106         
2107         if(pos >= size) {
2108                 return false;
2109         }
2110         
2111         // create d88 header
2112         d88_hdr_t d88_hdr;
2113         d88_sct_t d88_sct;
2114         
2115         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2116         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
2117         d88_hdr.protect = 0; // non-protected
2118         
2119         file_size.d = 0;
2120         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2121         
2122         // create tracks
2123         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
2124         int img_mode = -1;
2125         uint8_t dst[8192];
2126         
2127         while(pos < size) {
2128                 // check track header
2129                 uint8_t mode = tmp_buffer[pos++];
2130                 uint8_t track = tmp_buffer[pos++];
2131                 uint8_t head = tmp_buffer[pos++];
2132                 uint8_t sector_count = tmp_buffer[pos++];
2133                 uint8_t ssize = tmp_buffer[pos++];
2134                 
2135                 if(sector_count == 0) {
2136                         continue;
2137                 }
2138                 if(ssize == 0xff) {
2139                         return false;
2140                 }
2141                 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
2142                 
2143                 // setup sector id
2144                 const uint8_t *snum = &tmp_buffer[pos];
2145                 pos += sector_count;
2146                 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
2147                 if(tnum)
2148                         pos += sector_count;
2149                 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
2150                 if(hnum)
2151                         pos += sector_count;
2152                 head &= 0x3f;
2153                 
2154                 // create new track
2155                 int trkside = track * 2 + (head & 1);
2156                 if(trkside < 164) {
2157                         if(trkcnt < trkside) {
2158                                 trkcnt = trkside;
2159                         }
2160                         d88_hdr.trkptr[trkside] = trkptr;
2161                 }
2162                 if(img_mode == -1) {
2163                         img_mode = mode & 3;
2164                 }
2165                 
2166                 // read sectors in this track
2167                 for(int i = 0; i < sector_count; i++) {
2168                         // create d88 sector header
2169                         uint8_t stype = tmp_buffer[pos++];
2170                         memset(&d88_sct, 0, sizeof(d88_sct_t));
2171                         d88_sct.c = tnum ? tnum[i] : track;
2172                         d88_sct.h = hnum ? hnum[i] : head;
2173                         d88_sct.r = snum[i];
2174                         d88_sct.n = ssize;
2175                         d88_sct.nsec = sector_count;
2176                         d88_sct.dens = (mode < 3) ? 0x40 : 0;
2177                         
2178                         if(stype == 0 || stype > 8) {
2179                                 d88_sct.stat = 0xf0; // data mark missing
2180                                 d88_sct.size = 0;
2181                         } else {
2182                                 d88_sct.del  = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
2183                                 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
2184                                 d88_sct.size = actual_size;
2185                                 
2186                                 // create sector image
2187                                 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
2188                                         memset(dst, tmp_buffer[pos++], actual_size);
2189                                 } else {
2190                                         memcpy(dst, &tmp_buffer[pos], actual_size);
2191                                         pos += d88_sct.size;
2192                                 }
2193                         }
2194                         
2195                         // copy to d88
2196                         if(trkside < 164) {
2197                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2198                                 COPYBUFFER(dst, d88_sct.size);
2199                                 trkptr += sizeof(d88_sct_t) + d88_sct.size;
2200                         }
2201                 }
2202         }
2203         d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
2204         d88_hdr.size = trkptr;
2205         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2206         return true;
2207 }
2208
2209 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
2210
2211 #define DSK_FORMAT_HEADER       "MV - CPC"
2212 #define EXT_FORMAT_HEADER       "EXTENDED CPC DSK"
2213
2214 #pragma pack(1)
2215 struct track_header {
2216         uint8_t headertag[13];
2217         uint16_t unused1;
2218         uint8_t unused1b;
2219         uint8_t track_number;
2220         uint8_t side_number;
2221         uint8_t datarate;
2222         uint8_t rec_mode;
2223         uint8_t sector_size_code;
2224         uint8_t number_of_sector;
2225         uint8_t gap3_length;
2226         uint8_t filler_byte;
2227 };
2228 struct sector_header {
2229         uint8_t track;
2230         uint8_t side;
2231         uint8_t sector_id;
2232         uint8_t sector_size_code;
2233         uint8_t fdc_status_reg1;
2234         uint8_t fdc_status_reg2;
2235         uint16_t data_length;
2236 };
2237 #pragma pack()
2238
2239 bool DISK::cpdread_to_d88(FILEIO *fio)
2240 {
2241         bool extendformat = false;
2242         int image_size = fio->FileLength();
2243         
2244         fio->Fseek(0, FILEIO_SEEK_SET);
2245         fio->Fread(tmp_buffer, image_size, 1);
2246         
2247         if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
2248                 extendformat = true;
2249         } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
2250                 extendformat = false;
2251         } else {
2252                 return false;
2253         }
2254         
2255         int heads = tmp_buffer[0x31];
2256         int skip = 1;
2257         if(heads == 1) {
2258                 skip = 2;
2259         }
2260         int tracks = tmp_buffer[0x30];
2261         int track_offsets[84 * 2];
2262         bool track_offsets_error = false;
2263         if(!extendformat) {
2264                 int cnt = 0, tmp = 0x100;
2265                 for(int i = 0; i < tracks * heads; i++) {
2266                         track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2267                         if(track_offsets_error) {
2268                                 break;
2269                         }
2270                         track_offsets[cnt] = tmp;
2271                         tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
2272                         cnt += skip;
2273                 }
2274         } else  {
2275                 int cnt = 0, tmp = 0x100;
2276                 for(int i = 0; i < tracks * heads; i++) {
2277                         int length = tmp_buffer[0x34 + i] << 8;
2278                         if(length != 0) {
2279                                 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2280                                 if(track_offsets_error) {
2281                                         break;
2282                                 }
2283                                 track_offsets[cnt] = tmp;
2284                                 tmp += length;
2285                         } else {
2286                                 track_offsets[cnt] = image_size;
2287                         }
2288                         cnt += skip;
2289                 }
2290         }
2291         if(track_offsets_error) {
2292                 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
2293                 // so I modified this code to search "Track-Info" at the top of track information block
2294                 int cnt = 0, tmp = 0x100;
2295                 for(int i = 0; i < tracks * heads; i++) {
2296                         bool found = false;
2297                         for(; tmp < image_size; tmp += 0x10) {
2298                                 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
2299                                 if(found) {
2300                                         break;
2301                                 }
2302                         }
2303                         if(found) {
2304                                 track_offsets[cnt] = tmp;
2305                                 tmp += 0x10;
2306                         } else {
2307                                 track_offsets[cnt] = image_size;
2308                         }
2309                         cnt += skip;
2310                 }
2311         }
2312         
2313         // create d88 header
2314         d88_hdr_t d88_hdr;
2315         d88_sct_t d88_sct;
2316         
2317         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2318         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
2319         d88_hdr.protect = 0; // non-protected
2320         
2321         file_size.d = 0;
2322         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2323         
2324         // create tracks
2325         int total = 0, trkptr = sizeof(d88_hdr_t);
2326         
2327         for(int track = 0; track < tracks; track++) {
2328                 for(int side = 0; side < heads; side++) {
2329                         if(track_offsets[(track << 1) + side] >= image_size) {
2330                                 continue;
2331                         }
2332                         if((track << 1) + side < 164) {
2333                                 d88_hdr.trkptr[(track << 1) + side] = trkptr;
2334                         }
2335                         
2336                         track_header tr;
2337                         memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
2338                         int pos = track_offsets[(track << 1) + side] + 0x100;
2339                         for(int j = 0; j < tr.number_of_sector; j++) {
2340                                 sector_header sector;
2341                                 memcpy(&sector, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2342                                 
2343                                 // create d88 sector header
2344                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2345                                 d88_sct.c = sector.track;
2346                                 d88_sct.h = sector.side;
2347                                 d88_sct.r = sector.sector_id;
2348                                 d88_sct.n = sector.sector_size_code;
2349                                 d88_sct.nsec = tr.number_of_sector;
2350                                 if(extendformat) {
2351                                         d88_sct.size = sector.data_length;
2352                                         d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2353                                 } else {
2354                                         d88_sct.size = 128 << tr.sector_size_code;
2355                                         d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2356                                 }
2357                                 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2358                                 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2359                                 
2360                                 // copy to d88
2361                                 if((track << 1) + side < 164) {
2362                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2363                                         COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2364                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2365                                 }
2366                                 total += d88_sct.size;
2367                                 
2368                                 if(extendformat) {
2369                                         pos += sector.data_length;
2370                                 } else {
2371                                         pos += 128 << tr.sector_size_code;
2372                                 }
2373                         }
2374                 }
2375         }
2376         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2377         d88_hdr.size = trkptr;
2378         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2379         return true;
2380 }
2381
2382 // nfd r0/r1 image decoder
2383
2384 bool DISK::nfdr0_to_d88(FILEIO *fio)
2385 {
2386         // from NFD r0\8c`\8e®\83t\83@\83C\83\8b\8d\\91¢\8ed\97l 2001/01/22 LED
2387         typedef struct {
2388             BYTE  C;                            // C \81i0xFF\82Ì\8e\9e\83Z\83N\83^\96³\82µ\81j
2389             BYTE  H;                            // H
2390             BYTE  R;                            // R
2391             BYTE  N;                            // N
2392             BYTE  flMFM;                        // 0:FM / 1:MFM
2393             BYTE  flDDAM;                       // 0:DAM / 1:DDAM
2394             BYTE  byStatus;                     // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê
2395             BYTE  byST0;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST0
2396             BYTE  byST1;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST1
2397             BYTE  byST2;                        // READ DATA(FDDBIOS)\82Ì\8c\8b\89Ê ST2
2398             BYTE  byPDA;                        // FDDBIOS\82Å\8eg\97p\82·\82é\83A\83h\83\8c\83X
2399             char Reserve1[5];                   // \97\\96ñ
2400         }NFD_SECT_ID,*LP_NFD_SECT_ID;
2401         
2402         typedef struct {
2403             char  szFileID[15];                 // \8e¯\95ÊID "T98FDDIMAGE.R0"
2404             char  Reserve1[1];                  // \97\\96ñ
2405             char  szComment[0x100];             // \83C\83\81\81[\83W\83R\83\81\83\93\83g(ASCIIz)
2406             DWORD dwHeadSize;                   // \83w\83b\83_\95\94\82Ì\83T\83C\83Y
2407             BYTE  flProtect;                    // 0\88È\8aO : \83\89\83C\83g\83v\83\8d\83e\83N\83g
2408             BYTE  byHead;                       // \83w\83b\83h\90\94
2409             char  Reserve2[10];                 // \97\\96ñ
2410             NFD_SECT_ID si[163][26];            // \83Z\83N\83^ID(\8cã\8fq)
2411             char  Reserve3[0x10];               // \97\\96ñ
2412         }NFD_FILE_HEAD,*LP_NFD_FILE_HEAD;
2413         
2414         // check nfd header
2415         NFD_FILE_HEAD head;
2416         
2417         fio->Fseek(0, FILEIO_SEEK_SET);
2418         fio->Fread(&head, sizeof(head), 1);
2419         
2420         if(strncmp(head.szFileID, "T98FDDIMAGE.R0", 14) != 0) {
2421                 return false;
2422         }
2423         fio->Fseek(head.dwHeadSize, FILEIO_SEEK_SET);
2424         
2425         // create d88 header
2426         d88_hdr_t d88_hdr;
2427         d88_sct_t d88_sct;
2428         
2429         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2430         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "NFD R0");
2431         d88_hdr.protect = head.flProtect;
2432         
2433         file_size.d = 0;
2434         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2435         
2436         // create tracks
2437         int trkptr = sizeof(d88_hdr_t);
2438         
2439         for(int c = 0; c < 163; c++) {
2440                 int nsec = 0;
2441                 
2442                 for(int s = 0; s < 26; s++) {
2443                         if(head.si[c][s].C != 0xff) {
2444                                 nsec++;
2445                         }
2446                 }
2447                 if(nsec) {
2448                         d88_hdr.trkptr[c] = trkptr;
2449                         
2450                         // read sectors in this track
2451                         for(int s = 0; s < 26; s++) {
2452                                 if(head.si[c][s].C != 0xff) {
2453                                         // create d88 sector header
2454                                         memset(&d88_sct, 0, sizeof(d88_sct_t));
2455                                         d88_sct.c = head.si[c][s].C;
2456                                         d88_sct.h = head.si[c][s].H;
2457                                         d88_sct.r = head.si[c][s].R;
2458                                         d88_sct.n = head.si[c][s].N;
2459                                         d88_sct.nsec = nsec;
2460                                         d88_sct.dens = head.si[c][s].flMFM ? 0 : 0x40;
2461                                         d88_sct.del = head.si[c][s].flDDAM ? 0x10 : 0;
2462                                         if(head.si[c][s].byST1 & 0x20) {
2463                                                 if(head.si[c][s].byST2 & 0x20) {
2464                                                         d88_sct.stat = 0xb0; // data crc error
2465                                                 } else {
2466                                                         d88_sct.stat = 0xa0; // id crc error
2467                                                 }
2468                                         } else if(head.si[c][s].byST1 & 0x01) {
2469                                                 d88_sct.stat = 0xe0; // address mark missing
2470                                         } else if(head.si[c][s].byST2 & 0x01) {
2471                                                 d88_sct.stat = 0xf0; // data mark missing
2472                                         } else {
2473                                                 d88_sct.stat = d88_sct.del;
2474                                         }
2475                                         d88_sct.size = secsize[d88_sct.n & 3];
2476                                         
2477                                         // create sector image
2478                                         uint8_t dst[16384];
2479                                         memset(dst, 0xe5, sizeof(dst));
2480                                         fio->Fread(dst, d88_sct.size, 1);
2481                                         
2482                                         // copy to d88
2483                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2484                                         COPYBUFFER(dst, d88_sct.size);
2485                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2486                                         
2487                                         if(head.si[c][s].byPDA == 0x10) {
2488                                                 d88_hdr.type = MEDIA_TYPE_2DD;
2489                                         } else {
2490                                                 d88_hdr.type = MEDIA_TYPE_2HD;
2491                                         }
2492                                 }
2493                         }
2494                 }
2495         }
2496         d88_hdr.size = trkptr;
2497         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2498         return true;
2499 }
2500
2501 bool DISK::nfdr1_to_d88(FILEIO *fio)
2502 {
2503         // from NFD r1\8c`\8e®\83t\83@\83C\83\8b\8d\\91¢\8ed\97l 2001/09/14 LED
2504         typedef struct {
2505 //          char szFileID[sizeof(NFD_FILE_ID1)];        /* \8e¯\95ÊID "T98FDDIMAGE.R1"  */
2506 //          char Reserv1[0x10-sizeof(NFD_FILE_ID1)];    /* \97\\94õ                     */
2507             char  szFileID[15];                         /* \8e¯\95ÊID "T98FDDIMAGE.R1"  */
2508             char  Reserve1[1];                          /* \97\\96ñ                     */
2509             char szComment[0x100];                      /* \83R\83\81\83\93\83g                 */
2510             DWORD dwHeadSize;                           /* \83w\83b\83_\82Ì\83T\83C\83Y           */
2511             BYTE flProtect;                             /* \83\89\83C\83g\83v\83\8d\83e\83N\83g0\88È\8aO    */
2512             BYTE byHead;                                /* \83w\83b\83h\90\94 1-2             */
2513             char Reserv2[0x10-4-1-1];                   /* \97\\94õ                     */
2514             DWORD dwTrackHead[164];                     /* \83g\83\89\83b\83NID\88Ê\92u           */
2515             DWORD dwAddInfo;                            /* \92Ç\89Á\8fî\95ñ\83w\83b\83_\82Ì\83A\83h\83\8c\83X */
2516             char Reserv3[0x10-4];                       /* \97\\94õ                     */
2517         }NFD_FILE_HEAD1,*LP_NFD_FILE_HEAD1;
2518         
2519         typedef struct {
2520             WORD wSector;                               /* \83Z\83N\83^ID\90\94               */
2521             WORD wDiag;                                 /* \93Á\8eê ID\90\94                */
2522             char Reserv1[0x10-4];                       /* \97\\94õ                     */
2523         }NFD_TRACK_ID1,*LP_NFD_TRACK_ID1;
2524         
2525         typedef struct {
2526             BYTE    C;                                  /* C                        */
2527             BYTE    H;                                  /* H                        */
2528             BYTE    R;                                  /* R                        */
2529             BYTE    N;                                  /* N                        */
2530             BYTE    flMFM;                              /* MFM(1)/FM(0)             */
2531             BYTE    flDDAM;                             /* DDAM(1)/DAM(0)           */
2532             BYTE    byStatus;                           /* READ DATA RESULT         */
2533             BYTE    bySTS0;                             /* ST0                      */
2534             BYTE    bySTS1;                             /* ST1                      */
2535             BYTE    bySTS2;                             /* ST2                      */
2536             BYTE    byRetry;                            /* RetryData\82È\82µ(0)\82 \82è(1-) */
2537             BYTE    byPDA;                              /* PDA                      */
2538             char Reserv1[0x10-12];                      /* \97\\94õ                     */
2539         }NFD_SECT_ID1,*LP_NFD_SECT_ID1;
2540         
2541         typedef struct {
2542             BYTE    Cmd;                                /* Command                  */
2543             BYTE    C;                                  /* C                        */
2544             BYTE    H;                                  /* H                        */
2545             BYTE    R;                                  /* R                        */
2546             BYTE    N;                                  /* N                        */
2547             BYTE    byStatus;                           /* READ DATA RESULT         */
2548             BYTE    bySTS0;                             /* ST0                      */
2549             BYTE    bySTS1;                             /* ST1                      */
2550             BYTE    bySTS2;                             /* ST2                      */
2551             BYTE    byRetry;                            /* RetryData\82È\82µ(0)\82 \82è(1-) */
2552             DWORD   dwDataLen;
2553             BYTE    byPDA;                              /* PDA                      */
2554             char Reserv1[0x10-15];                      /* \97\\94õ                     */
2555         }NFD_DIAG_ID1,*LP_NFD_DIAG_ID1;
2556         
2557         // check nfd header
2558         NFD_FILE_HEAD1 head;
2559         
2560         fio->Fseek(0, FILEIO_SEEK_SET);
2561         fio->Fread(&head, sizeof(head), 1);
2562         
2563         if(strncmp(head.szFileID, "T98FDDIMAGE.R1", 14) != 0) {
2564                 return false;
2565         }
2566         fio->Fseek(head.dwHeadSize, FILEIO_SEEK_SET);
2567         
2568         // not implemented yet :-(
2569         return false;
2570 }
2571
2572 // solid image decoder
2573
2574 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2575 {
2576         int n = 0, t = 0;
2577         
2578         media_type = type;
2579         solid_ncyl = ncyl;
2580         solid_nside = nside;
2581         solid_nsec = nsec;
2582         solid_size = size;
2583         solid_mfm = mfm;
2584         
2585         // create d88 header
2586         d88_hdr_t d88_hdr;
2587         d88_sct_t d88_sct;
2588         
2589         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2590         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2591         d88_hdr.protect = 0; // non-protected
2592         
2593         file_size.d = 0;
2594         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2595         
2596         // sector length
2597         for(int i = 0; i < 8; i++) {
2598                 if(size == (128 << i)) {
2599                         n = i;
2600                         break;
2601                 }
2602         }
2603         
2604         // create tracks
2605         int trkptr = sizeof(d88_hdr_t);
2606         
2607         for(int c = 0; c < ncyl; c++) {
2608                 for(int h = 0; h < nside; h++) {
2609                         d88_hdr.trkptr[t++] = trkptr;
2610                         if(nside == 1) {
2611                                 t++;
2612                         }
2613                         
2614                         // read sectors in this track
2615                         for(int s = 0; s < nsec; s++) {
2616                                 // create d88 sector header
2617                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2618                                 d88_sct.c = c;
2619                                 d88_sct.h = h;
2620                                 d88_sct.r = s + 1;
2621                                 d88_sct.n = n;
2622                                 d88_sct.nsec = nsec;
2623                                 d88_sct.dens = 0;
2624                                 d88_sct.del = 0;
2625                                 d88_sct.stat = 0;
2626                                 d88_sct.size = size;
2627                                 
2628                                 // create sector image
2629                                 uint8_t dst[16384];
2630                                 memset(dst, 0xe5, sizeof(dst));
2631                                 fio->Fread(dst, size, 1);
2632                                 
2633                                 // copy to d88
2634                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2635                                 COPYBUFFER(dst, size);
2636                                 trkptr += sizeof(d88_sct_t) + size;
2637                         }
2638                 }
2639         }
2640         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2641         d88_hdr.size = trkptr;
2642         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2643         return true;
2644 }
2645
2646 #define STATE_VERSION   13
2647
2648 bool DISK::process_state(FILEIO* state_fio, bool loading)
2649 {
2650         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
2651                 return false;
2652         }
2653         state_fio->StateArray(buffer, sizeof(buffer), 1);
2654         state_fio->StateArray(orig_path, sizeof(orig_path), 1);
2655         state_fio->StateArray(dest_path, sizeof(dest_path), 1);
2656         state_fio->StateValue(file_size.d);
2657         state_fio->StateValue(file_bank);
2658         state_fio->StateValue(orig_file_size);
2659         state_fio->StateValue(orig_crc32);
2660         state_fio->StateValue(trim_required);
2661         state_fio->StateValue(is_1dd_image);
2662         state_fio->StateValue(is_solid_image);
2663         state_fio->StateValue(is_fdi_image);
2664         state_fio->StateArray(fdi_header, sizeof(fdi_header), 1);
2665         state_fio->StateValue(solid_ncyl);
2666         state_fio->StateValue(solid_nside);
2667         state_fio->StateValue(solid_nsec);
2668         state_fio->StateValue(solid_size);
2669         state_fio->StateValue(solid_mfm);
2670         state_fio->StateValue(inserted);
2671         state_fio->StateValue(ejected);
2672         state_fio->StateValue(write_protected);
2673         state_fio->StateValue(changed);
2674         state_fio->StateValue(media_type);
2675         state_fio->StateValue(is_special_disk);
2676         state_fio->StateArray(track, sizeof(track), 1);
2677         state_fio->StateValue(sector_num.sd);
2678         state_fio->StateValue(track_mfm);
2679         state_fio->StateValue(invalid_format);
2680 //      state_fio->StateValue(no_skew);
2681         state_fio->StateArray(sync_position, sizeof(sync_position), 1);
2682         state_fio->StateArray(am1_position, sizeof(am1_position), 1);
2683         state_fio->StateArray(id_position, sizeof(id_position), 1);
2684         state_fio->StateArray(data_position, sizeof(data_position), 1);
2685 //      state_fio->StateValue(gap3_size);
2686         if(loading) {
2687                 int offset = state_fio->FgetInt32_LE();
2688                 sector = (offset != -1) ? buffer + offset : NULL;
2689         } else {
2690                 state_fio->FputInt32_LE(sector ? (int)(sector - buffer) : -1);
2691         }
2692         state_fio->StateValue(sector_size.sd);
2693         state_fio->StateArray(id, sizeof(id), 1);
2694         state_fio->StateValue(density);
2695         state_fio->StateValue(deleted);
2696         state_fio->StateValue(addr_crc_error);
2697         state_fio->StateValue(data_crc_error);
2698         state_fio->StateValue(drive_type);
2699         state_fio->StateValue(drive_rpm);
2700         state_fio->StateValue(drive_mfm);
2701         return true;
2702 }
2703