OSDN Git Service

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