OSDN Git Service

[VM][General] Merge Upstream 2017-12-15.
[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(".2d"))  && file_size.d == 40 * 2 * 16 * 256) {
266                         // 2d image for SHARP X1 series
267                         try {
268                                 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true)) {
269                                         inserted = changed = is_solid_image = true;
270                                 }
271                         } catch(...) {
272                                 // failed to convert the disk image
273                         }
274                 } else if(check_file_extension(file_path, _T(".img"))  && file_size.d == 70 * 1 * 16 * 256) {
275                         // img image for SONY SMC-70/777 series
276                         try {
277                                 if(solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true)) {
278                                         inserted = changed = is_solid_image = true;
279                                 }
280                         } catch(...) {
281                                 // failed to convert the disk image
282                         }
283                 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
284                         // sf7 image for SEGA SC-3000 + SF-7000
285                         try {
286                                 if(solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true)) {
287                                         inserted = changed = is_solid_image = true;
288                                 }
289                         } catch(...) {
290                                 // failed to convert the disk image
291                         }
292                 }
293                 if(!inserted) {
294                         // check solid image file format
295                         bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
296                         for(int i = 0;; i++) {
297                                 const fd_format_t *p = &fd_formats[i];
298                                 if(p->type == -1) {
299                                         break;
300                                 }
301                                 int len = p->ncyl * p->nside * p->nsec * p->size;
302                                 // 4096 bytes: FDI header ???
303                                 if(file_size.d == (uint32_t)(len + (is_fdi_tmp ? 4096 : 0))) {
304                                         fio->Fseek(0, FILEIO_SEEK_SET);
305                                         if(is_fdi_tmp) {
306                                                 is_fdi_image = true;
307                                                 fio->Fread(fdi_header, 4096, 1);
308                                         }
309                                         int type = p->type;
310                                         int ncyl = p->ncyl;
311                                         int nside = p->nside;
312                                         int nsec = p->nsec;
313                                         int size = p->size;
314 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
315                                                 if(type_1dd) {
316                                                         if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
317                                                                 type = MEDIA_TYPE_2DD;
318                                                                 nside = 1;
319                                                                 ncyl *= 2;
320                                                         }
321                                                 } else if(type_any2d88) {
322 //#elif defined(_ANY2D88)
323                                                         if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
324                                                                 type = MEDIA_TYPE_2DD;
325                                                                 nside = 1;
326                                                                 ncyl *= 2;
327                                                         }
328                                                         if(open_as_256 && (size == 512 || size == 1024)) {
329                                                                 nsec *= size / 256;
330                                                                 size = 256;
331                                                         }
332                                                 }
333 //#endif
334                                         try {
335 //                                              if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
336                                                 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
337                                                         inserted = changed = is_solid_image = true;
338                                                 }
339                                         } catch(...) {
340                                                 // failed to convert the disk image
341                                         }
342                                         if(inserted) {
343                                                 break;
344                                         }
345                                 }
346                         }
347                 }
348                 if(fio->IsOpened()) {
349                         fio->Fclose();
350                 }
351         }
352         delete fio;
353         
354         // check loaded image
355         if(inserted) {
356                 // check media type
357                 if(media_type == MEDIA_TYPE_UNK) {
358                         if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
359                                 // check 1.2MB or 1.44MB
360                                 for(int trkside = 0; trkside < 164; trkside++) {
361                                         pair_t offset;
362                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
363                                         
364                                         if(!IS_VALID_TRACK(offset.d)) {
365                                                 continue;
366                                         }
367                                         // track found
368                                         uint8_t *t = buffer + offset.d;
369                                         pair_t sector_num, data_size;
370                                         sector_num.read_2bytes_le_from(t + 4);
371                                         data_size.read_2bytes_le_from(t + 14);
372                                         
373                                         if(sector_num.sd >= 18 && data_size.sd == 512) {
374                                                 media_type = MEDIA_TYPE_144;
375                                         }
376                                         break;
377                                 }
378                         }
379                 }
380                 
381                 // fix write protect flag
382                 if(buffer[0x1a] != 0) {
383                         buffer[0x1a] = 0x10;
384                         write_protected = true;
385                 }
386                 
387                 // get crc32 for midification check
388                 orig_file_size = file_size.d;
389                 orig_crc32 = get_crc32(buffer, file_size.d);
390                 
391                 // check special disk image
392 //#if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
393                 if(type_fm7) {
394                         // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
395                         if(media_type == MEDIA_TYPE_2D) {
396                                 // check first track
397                                 pair_t offset, sector_num, data_size;
398                                 offset.read_4bytes_le_from(buffer + 0x20);
399
400                                 if(IS_VALID_TRACK(offset.d)) {
401                                         // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
402                                         uint8_t* t = buffer + offset.d;
403                                         sector_num.read_2bytes_le_from(t + 4);
404                                         for(int _i = 0; _i < sector_num.sd; _i++) {
405                                                 data_size.read_2bytes_le_from(t + 14);
406                                                 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
407                                                         /* Type 1: Sec07, +$50- "1989/09/12 ... "*/
408                                                         static const uint8_t gamblerfm_1[] = {
409                                                                 0x31, 0x39, 0x38, 0x39, 0x2f, 0x30, 0x39, 0x2f,
410                                                                 0x31, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411                                                                 0x28, 0x43, 0x29, 0x47, 0x41, 0x4d, 0x45, 0x41,
412                                                                 0x52, 0x54, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
413                                                                 0x20, 0x20, 0x20, 0x59, 0x45, 0x4c, 0x4c, 0x4f,
414                                                                 0x57, 0x48, 0x4f, 0x52, 0x4e, 0x00, 0x00, 0x00,
415                                                                 0x20, 0x20, 0x20, 0x4b, 0x4f, 0x55, 0x44, 0x41,
416                                                                 0x4e, 0x53, 0x59, 0x41, 0x20, 0x59, 0x4f, 0x55,
417                                                                 0x4e, 0x47, 0x2d, 0x4d, 0x41, 0x47, 0x41, 0x5a,
418                                                                 0x49, 0x4e, 0x45, 0x00 
419                                                         };
420                                                         /* Type 2: Sec07, +$30- */
421                                                         static const uint8_t gamblerfm_2[] = {
422                                                                 0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7,
423                                                                 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3,
424                                                                 0xbc, 0xdd, 0xca
425                                                         };
426                                                         if(memcmp((void *)(t + 0x50), gamblerfm_1, sizeof(gamblerfm_1)) == 0) {
427                                                                 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
428                                                                 break;
429                                                         }
430                                                         if(memcmp((void *)(t + 0x30), gamblerfm_2, sizeof(gamblerfm_2)) == 0) {
431                                                                 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
432                                                                 break;
433                                                         }
434                                                 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
435                                                         //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
436                                                         static const uint8_t deathforce[] ={
437                                                                 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
438                                                                 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
439                                                                 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
440                                                                 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
441                                                                 0x00, 0x00
442                                                         };
443                                                         if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
444                                                                 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
445                                                                 break;
446                                                         }
447                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 5 && t[3] == 1) {
448                                                         //$00 * 16 + $00 + "Protected by  N & A (SUPER HACKER COMBI)
449                                                         //Can you found CHECK-ROUTINES ?Can you crack these protect ?
450                                                         //good bye !ou "
451                                                         static const uint8_t xanadu2fm_d_1[] ={
452                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454                                                         };
455                                                         static const uint8_t xanadu2fm_d_2[] = {
456                                                                 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x65,
457                                                                 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x4E, 0x20,
458                                                                 0x26, 0x20, 0x41, 0x20, 0x28, 0x53, 0x55, 0x50,
459                                                                 0x45, 0x52, 0x20, 0x48, 0x41, 0x43, 0x4B, 0x45,
460                                                                 0x52, 0x20, 0x43, 0x4F, 0x4D, 0x42, 0x49, 0x29,
461                                                                 0x43, 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20,
462                                                                 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x43, 0x48,
463                                                                 0x45, 0x43, 0x4B, 0x2D, 0x52, 0x4F, 0x55, 0x54,
464                                                                 0x49, 0x4E, 0x45, 0x53, 0x20, 0x3F, 0x43, 0x61,
465                                                                 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x72,
466                                                                 0x61, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x73,
467                                                                 0x65, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63,
468                                                                 0x74, 0x20, 0x3F, 0x67, 0x6F, 0x6F, 0x64, 0x20,
469                                                                 0x62, 0x79, 0x65, 0x20, 0x21, 0x6F, 0x75, 0x20,
470                                                         };
471                                                         if(memcmp((void *)(t + 0x10 + 0x60), xanadu2fm_d_1, sizeof(xanadu2fm_d_1)) == 0) {
472                                                                 if(memcmp((void *)(t + 0x10 + 0x70), xanadu2fm_d_2, sizeof(xanadu2fm_d_2)) == 0) {
473                                                                         is_special_disk = SPECIAL_DISK_FM7_XANADU2_D;
474                                                                         break;
475                                                                 }
476                                                         }
477                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 8 && t[3] == 1) {
478                                                         // Xanadu 1
479                                                         static const uint8_t xanadu1fm_d_1[] = {
480                                                                 0xFF, 0x43, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75,
481                                                                 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70,
482                                                                 0x72, 0x6F, 0x67, 0x72, 0x61 ,0x6D, 0x2E, 0x0D,
483                                                                 0xFF, 0x00, 0x34, 0x01, 0x1C ,0xAF, 0x6F, 0x8D,
484                                                                 0x01, 0x3F, 0x17, 0xFA, 0xE4, 0x27, 0xFB, 0x35,
485                                                                 0x81, 0x34, 0x13, 0xA6, 0x80, 0x81, 0xFF, 0x27,
486                                                                 0x04, 0x8D, 0x04, 0x20, 0xF6, 0x35, 0x93, 0x34,
487                                                                 0x15, 0xA7, 0x8D, 0x00, 0xB6, 0xC6, 0x05, 0x30,
488                                                                 0x8D, 0x00, 0xAC, 0x17, 0x00, 0xB6, 0x17, 0x00,
489                                                                 0xD6, 0x35, 0x95, 0x00, 0x00, 0x3F, 0x59, 0x41,
490                                                                 0x4D, 0x41, 0x55, 0x43, 0x48, 0x49, 0x91, 0xD3,
491                                                         };
492                                                         static const uint8_t xanadu1fm_d_2[] = {
493                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494                                                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495                                                                 0x00, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x41, 0x4D,
496                                                                 0x41, 0x55, 0x43, 0x48, 0x49, 0x93, 0xD3, 0x8F,
497                                                                 0x90, 0x8E, 
498                                                         };
499                                                         if(memcmp((void *)(t + 0x10 + 0), xanadu1fm_d_1, sizeof(xanadu1fm_d_1)) == 0) {
500                                                                 if(memcmp((void *)(t + 0x10 + 0xb0), xanadu1fm_d_2, sizeof(xanadu1fm_d_2)) == 0) {
501                                                                         is_special_disk = SPECIAL_DISK_FM7_XANADU2_D; // Same issue as Xanadu2.
502                                                                         break;
503                                                                 }
504                                                         }
505                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
506                                                         //$03 + $2D + "PSY-O-BLADE   Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
507                                                         static const uint8_t psyoblade_ipl1[] ={
508                                                                 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
509                                                                 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
510                                                                 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
511                                                                 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
512                                                                 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
513                                                                 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
514                                                                 0xfd, 0x05
515                                                         };
516                                                         //IPL Signature1
517                                                         static const uint8_t psyoblade_disk_1[] ={
518                                                                 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
519                                                                 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
520                                                                 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
521                                                                 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
522                                                         };
523                                                         //$00 + $00 + $03 + $14 + "PSY-O-BLADE  DISK" + $B6 + $FD + $05
524                                                         static const uint8_t psyoblade_disk_2[] ={
525                                                                 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
526                                                                 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
527                                                                 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
528                                                         };
529                                                         //RIGLAS/FM: $3E - $7D 
530                                                         static const uint8_t riglas_fm[] = {
531                                                                 0x0d, 0x56, /* $3e-$3f */
532                                                                 0x44, 0x53, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, /* $40-$47 */
533                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1b, 0x02, /* $48-$4f */
534                                                                 0x1e, 0x00, 0x04, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $50-$57 */
535                                                                 0x43, 0x4f, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00, /* $58-$5f */
536                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x02, 0x1f, 0x03, /* $60-$67 */
537                                                                 0x03, 0x00, 0x05, 0x00, 0x00, 0x03, 0x0d, 0x56, /* $68-$6f */
538                                                                 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x00, 0x00, /* $70-$77 */
539                                                                 0x43, 0x4d, 0x44, 0x00, 0x00, 0x03              /* $78-$7d */
540                                                         };
541                                                         if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
542                                                                 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
543                                                                 break;
544                                                         } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
545                                                                 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
546                                                                         is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
547                                                                         break;
548                                                                 }
549                                                         } else if(memcmp((void *)(t + 0x3e + 0x10), riglas_fm, sizeof(riglas_fm)) == 0) {
550                                                                 is_special_disk = SPECIAL_DISK_FM7_RIGLAS;
551                                                                 break;
552                                                         }
553                                         } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
554                                                         static const uint8_t taiyoufm1[] = {
555                                                                 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
556                                                                 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
557                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
558                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
559                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
560                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
561                                                                 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
562                                                                 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
563                                                                 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
564                                                                 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
565                                                         };
566                                                         if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
567                                                                 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
568                                                                 break;
569                                                         }
570                                                 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
571                                                         static const uint8_t taiyoufm2[] = {
572                                                                 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
573                                                                 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
574                                                                 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
575                                                                 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
576                                                                 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
577                                                                 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
578                                                                 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
579                                                                 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
580                                                         };
581                                                         if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
582                                                                 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
583                                                                 break;
584                                                         }
585                                                 }
586                                                 t += data_size.sd + 0x10;
587                                         }
588                                 }
589                         }
590                 } else if(type_x1) { 
591 //#elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
592                         // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
593                         if(media_type == MEDIA_TYPE_2D) {
594                                 // check first track
595                                 pair_t offset;
596                                 offset.read_4bytes_le_from(buffer + 0x20);
597                                 if(IS_VALID_TRACK(offset.d)) {
598                                         // check first sector
599                                         static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
600                                         uint8_t *t = buffer + offset.d;
601 //#if defined(_X1TURBO) || defined(_X1TURBOZ)
602 //                              if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
603 //                                      is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
604 //                              } else
605 //#endif
606                                                 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
607                                                         is_special_disk = SPECIAL_DISK_X1_BATTEN;
608                                                 }
609                                 }
610                         }
611                 }
612 //#endif
613         }
614 }
615
616 void DISK::close()
617 {
618         // write disk image
619         if(inserted) {
620                 if(trim_required) {
621                         trim_buffer();
622                         trim_required = false;
623                 }
624                 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
625                 
626                 if(/*!write_protected &&*/ !(file_size.d == orig_file_size && get_crc32(buffer, file_size.d) == orig_crc32)) {
627                         // write image
628                         FILEIO* fio = new FILEIO();
629                         int pre_size = 0, post_size = 0;
630                         uint8_t *pre_buffer = NULL, *post_buffer = NULL;
631                         
632                         // is this d88 format ?
633                         if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
634                                 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
635                                         fio->Fseek(0, FILEIO_SEEK_END);
636                                         uint32_t total_size = fio->Ftell(), offset = 0;
637                                         for(int i = 0; i < file_bank; i++) {
638                                                 fio->Fseek(offset + 0x1c, SEEK_SET);
639                                                 offset += fio->FgetUint32_LE();
640                                         }
641                                         if((pre_size = offset) > 0) {
642                                                 pre_buffer = (uint8_t *)malloc(pre_size);
643                                                 fio->Fseek(0, FILEIO_SEEK_SET);
644                                                 fio->Fread(pre_buffer, pre_size, 1);
645                                         }
646                                         fio->Fseek(offset + 0x1c, SEEK_SET);
647                                         offset += fio->FgetUint32_LE();
648                                         if((post_size = total_size - offset) > 0) {
649                                                 post_buffer = (uint8_t *)malloc(post_size);
650                                                 fio->Fseek(offset, FILEIO_SEEK_SET);
651                                                 fio->Fread(post_buffer, post_size, 1);
652                                         }
653                                         fio->Fclose();
654                                 }
655                         }
656                         
657                         // is this solid image and was physical formatted ?
658                         if(is_solid_image) {
659                                 bool formatted = false;
660                                 int tracks = 0;
661                                 
662                                 for(int trkside = 0; trkside < 164; trkside++) {
663                                         pair_t offset;
664                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
665                                         
666                                         if(!IS_VALID_TRACK(offset.d)) {
667                                                 continue;
668                                         }
669                                         if(solid_nside == 1 && (trkside & 1) == 1) {
670                                                 formatted = true;
671                                         }
672                                         tracks++;
673                                         
674                                         uint8_t* t = buffer + offset.d;
675                                         pair_t sector_num, data_size;
676                                         sector_num.read_2bytes_le_from(t + 4);
677                                         
678                                         if(sector_num.sd != solid_nsec) {
679                                                 formatted = true;
680                                         }
681                                         for(int i = 0; i < sector_num.sd; i++) {
682                                                 data_size.read_2bytes_le_from(t + 14);
683                                                 if(data_size.sd != solid_size) {
684                                                         formatted = true;
685                                                 }
686                                                 if(t[6] != (solid_mfm ? 0 : 0x40)) {
687                                                         formatted = true;
688                                                 }
689                                                 t += data_size.sd + 0x10;
690                                         }
691                                 }
692                                 if(tracks != (solid_ncyl * solid_nside)) {
693                                         formatted = true;
694                                 }
695                                 if(formatted) {
696                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
697                                         is_solid_image = false;
698                                 }
699                         }
700                         
701                         if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
702                                 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
703                         }
704                         if(fio->IsOpened()) {
705                                 if(pre_buffer) {
706                                         fio->Fwrite(pre_buffer, pre_size, 1);
707                                 }
708                                 if(is_solid_image) {
709                                         if(is_fdi_image) {
710                                                 fio->Fwrite(fdi_header, 4096, 1);
711                                         }
712                                         for(int trkside = 0; trkside < 164; trkside++) {
713                                                 pair_t offset;
714                                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
715                                                 
716                                                 if(!IS_VALID_TRACK(offset.d)) {
717                                                         continue;
718                                                 }
719                                                 uint8_t* t = buffer + offset.d;
720                                                 pair_t sector_num, data_size;
721                                                 sector_num.read_2bytes_le_from(t + 4);
722                                                 
723                                                 for(int i = 0; i < sector_num.sd; i++) {
724                                                         data_size.read_2bytes_le_from(t + 14);
725                                                         fio->Fwrite(t + 0x10, data_size.sd, 1);
726                                                         t += data_size.sd + 0x10;
727                                                 }
728                                         }
729                                 } else {
730                                         fio->Fwrite(buffer, file_size.d, 1);
731                                 }
732                                 if(post_buffer) {
733                                         fio->Fwrite(post_buffer, post_size, 1);
734                                 }
735                                 fio->Fclose();
736                         }
737                         if(pre_buffer) {
738                                 free(pre_buffer);
739                         }
740                         if(post_buffer) {
741                                 free(post_buffer);
742                         }
743                         delete fio;
744                 }
745                 ejected = true;
746         }
747         inserted = write_protected = false;
748         file_size.d = 0;
749         sector_size.sd = sector_num.sd = 0;
750         sector = NULL;
751 }
752
753 //#ifdef _ANY2D88
754 void DISK::save_as_d88(const _TCHAR* file_path)
755 {
756 //#ifdef _ANY2D88
757         if(inserted) {
758                 FILEIO* fio = new FILEIO();
759                 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
760                         if(is_1dd_image) {
761                                 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
762                                 for(int trk = 0; trk < 82; trk++) {
763                                         memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
764                                         memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
765                                 }
766                                 buffer[0x1b] = MEDIA_TYPE_2DD;
767                         }
768                         fio->Fwrite(buffer, file_size.d, 1);
769                         fio->Fclose();
770                 }
771                 delete fio;
772         }
773 //#endif
774 }
775 //#endif
776
777 bool DISK::get_track(int trk, int side)
778 {
779         sector_size.sd = sector_num.sd = 0;
780         invalid_format = false;
781 //      no_skew = true;
782         
783         // disk not inserted or invalid media type
784         if(!(inserted && check_media_type())) {
785                 return false;
786         }
787         
788         // search track
789         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
790         if(!(0 <= trkside && trkside < 164)) {
791                 return false;
792         }
793         cur_track = trk;
794         cur_side = side;
795         
796         pair_t offset;
797         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
798         
799         if(!IS_VALID_TRACK(offset.d)) {
800                 return false;
801         }
802         
803         // track found
804         sector = buffer + offset.d;
805         sector_num.read_2bytes_le_from(sector + 4);
806         pair_t data_size;
807         data_size.read_2bytes_le_from(sector + 14);
808         
809         // create each sector position in track
810         track_mfm = false;
811         if(sector_num.sd == 0) {
812                 track_mfm = drive_mfm;
813         } else {
814                 uint8_t* t = sector;
815                 for(int i = 0; i < sector_num.sd; i++) {
816                         data_size.read_2bytes_le_from(t + 14);
817                         // t[6]: 0x00 = double-density, 0x40 = single-density
818                         if(t[6] == 0x00) {
819                                 track_mfm = true;
820                                 break;
821                         }
822                         t += data_size.sd + 0x10;
823                 }
824         }
825         int sync_size  = track_mfm ? 12 : 6;
826         int am_size = track_mfm ? 3 : 0;
827         int gap0_size = track_mfm ? 80 : 40;
828         int gap1_size = track_mfm ? 50 : 26;
829         int gap2_size = track_mfm ? 22 : 11;
830         int gap3_size = 0, gap4_size;
831         
832         if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
833                 if(track_mfm) {
834                         if(data_size.sd ==  256 && sector_num.sd == 26) gap3_size =  54;
835                         if(data_size.sd ==  512 && sector_num.sd == 15) gap3_size =  84;
836                         if(data_size.sd == 1024 && sector_num.sd ==  8) gap3_size = 116;
837                 } else {
838                         if(data_size.sd ==  128 && sector_num.sd == 26) gap3_size =  27;
839                         if(data_size.sd ==  256 && sector_num.sd == 15) gap3_size =  42;
840                         if(data_size.sd ==  512 && sector_num.sd ==  8) gap3_size =  58;
841                 }
842         } else {
843                 if(track_mfm) {
844                         if(data_size.sd ==  256 && sector_num.sd == 16) gap3_size =  51;
845                         if(data_size.sd ==  512 && sector_num.sd ==  9) gap3_size =  80;
846                         if(data_size.sd == 1024 && sector_num.sd ==  5) gap3_size = 116;
847                 } else {
848                         if(data_size.sd ==  128 && sector_num.sd == 16) gap3_size =  27;
849                         if(data_size.sd ==  256 && sector_num.sd ==  9) gap3_size =  42;
850                         if(data_size.sd ==  512 && sector_num.sd ==  5) gap3_size =  58;
851                 }
852         }
853         
854         uint8_t* t = sector;
855         int total = 0, valid_sector_num = 0;
856         
857         for(int i = 0; i < sector_num.sd; i++) {
858                 data_size.read_2bytes_le_from(t + 14);
859                 sync_position[i] = total; // for invalid format case
860                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
861                 if(data_size.sd > 0) {
862                         total += sync_size + (am_size + 1);
863                         total += data_size.sd + 2;
864                         valid_sector_num++;
865                 }
866 //              if(t[2] != i + 1) {
867 //                      no_skew = false;
868 //              }
869                 t += data_size.sd + 0x10;
870         }
871         total += sync_size + (am_size + 1); // sync in preamble
872         
873         if(gap3_size == 0) {
874                 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
875         }
876         gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
877         
878         if(gap3_size < 8 || gap4_size < 8) {
879                 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
880                 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
881         }
882         if(gap3_size < 8 || gap4_size < 8) {
883                 gap0_size = gap1_size = gap3_size = gap4_size = 8;
884                 invalid_format = true;
885         }
886         int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
887         
888         if(invalid_format) {
889                 total -= sync_size + (am_size + 1);
890                 for(int i = 0; i < sector_num.sd; i++) {
891                         sync_position[i] *= get_track_size() - preamble_size - gap4_size;
892                         sync_position[i] /= total;
893                 }
894         }
895         t = sector;
896         total = preamble_size;
897         sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
898         
899         for(int i = 0; i < sector_num.sd; i++) {
900                 data_size.read_2bytes_le_from(t + 14);
901                 if(invalid_format) {
902                         total = preamble_size + sync_position[i];
903                 }
904                 sync_position[i] = total;
905                 total += sync_size;
906                 am1_position[i] = total;
907                 total += am_size + 1;
908                 id_position[i] = total;
909                 total += (4 + 2) + gap2_size;
910                 if(data_size.sd > 0) {
911                         total += sync_size + (am_size + 1);
912                         data_position[i] = total;
913                         total += data_size.sd + 2;
914                         total += gap3_size;
915                 } else {
916                         data_position[i] = total; // FIXME
917                 }
918                 t += data_size.sd + 0x10;
919         }
920         return true;
921 }
922
923 bool DISK::make_track(int trk, int side)
924 {
925         int track_size = get_track_size();
926         
927         if(!get_track(trk, side)) {
928                 // create a dummy track
929                 for(int i = 0; i < track_size; i++) {
930                         track[i] = rand();
931                 }
932                 return false;
933         }
934         
935         // make track image
936         int sync_size  = track_mfm ? 12 : 6;
937         int am_size = track_mfm ? 3 : 0;
938         int gap2_size = track_mfm ? 22 : 11;
939         uint8_t gap_data = track_mfm ? 0x4e : 0xff;
940         
941         // preamble
942         memset(track, gap_data, track_size);
943         int q = sync_position[array_length(sync_position) - 1];
944         
945         // sync
946         for(int i = 0; i < sync_size; i++) {
947                 track[q++] = 0x00;
948         }
949         // index mark
950         for(int i = 0; i < am_size; i++) {
951                 track[q++] = 0xc2;
952         }
953         track[q++] = 0xfc;
954         
955         // sectors
956         uint8_t *t = sector;
957         
958         for(int i = 0; i < sector_num.sd; i++) {
959                 pair_t data_size;
960                 data_size.read_2bytes_le_from(t + 14);
961                 int p = sync_position[i];
962                 
963                 // sync
964                 for(int j = 0; j < sync_size; j++) {
965                         if(p < track_size) track[p++] = 0x00;
966                 }
967                 // am1
968                 uint16_t crc = 0xffff;
969                 for(int j = 0; j < am_size; j++) {
970                         if(p < track_size) track[p++] = 0xa1;
971                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
972                 }
973                 if(p < track_size) track[p++] = 0xfe;
974                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
975                 // id
976                 if(p < track_size) track[p++] = t[0];
977                 if(p < track_size) track[p++] = t[1];
978                 if(p < track_size) track[p++] = t[2];
979                 if(p < track_size) track[p++] = t[3];
980                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
981                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
982                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
983                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
984                 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
985                 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
986                 // gap2
987                 for(int j = 0; j < gap2_size; j++) {
988                         if(p < track_size) track[p++] = gap_data;
989                 }
990                 // data field
991                 if(data_size.sd > 0) {
992                         // sync
993                         for(int j = 0; j < sync_size; j++) {
994                                 if(p < track_size) track[p++] = 0x00;
995                         }
996                         // am2
997                         crc = 0xffff;
998                         for(int j = 0; j < am_size; j++) {
999                                 if(p < track_size) track[p++] = 0xa1;
1000                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1001                         }
1002                         uint8_t am2 = (t[7] != 0) ? 0xf8 : 0xfb;
1003                         if(p < track_size) track[p++] = am2;
1004                         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ am2]);
1005                         // data
1006                         for(int j = 0; j < data_size.sd; j++) {
1007                                 if(p < track_size) track[p++] = t[0x10 + j];
1008                                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
1009                         }
1010                         if(p < track_size) track[p++] = (crc >> 8) & 0xff;
1011                         if(p < track_size) track[p++] = (crc >> 0) & 0xff;
1012                 }
1013                 t += data_size.sd + 0x10;
1014         }
1015         return true;
1016 }
1017
1018 bool DISK::get_sector(int trk, int side, int index)
1019 {
1020         sector_size.sd = sector_num.sd = 0;
1021         sector = NULL;
1022         
1023         // disk not inserted or invalid media type
1024         if(!(inserted && check_media_type())) {
1025                 return false;
1026         }
1027         
1028         // search track
1029         if(trk == -1 && side == -1) {
1030                 trk = cur_track;
1031                 side = cur_side;
1032         }
1033         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1034         if(!(0 <= trkside && trkside < 164)) {
1035                 return false;
1036         }
1037         pair_t offset;
1038         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1039         
1040         if(!IS_VALID_TRACK(offset.d)) {
1041                 return false;
1042         }
1043         
1044         // track found
1045         uint8_t* t = buffer + offset.d;
1046         sector_num.read_2bytes_le_from(t + 4);
1047         
1048         if(index >= sector_num.sd) {
1049                 return false;
1050         }
1051         
1052         // skip sector
1053         for(int i = 0; i < index; i++) {
1054                 pair_t data_size;
1055                 data_size.read_2bytes_le_from(t + 14);
1056                 t += data_size.sd + 0x10;
1057         }
1058         set_sector_info(t);
1059         return true;
1060 }
1061
1062 void DISK::set_sector_info(uint8_t *t)
1063 {
1064         // header info
1065         int am_size = track_mfm ? 3 : 0;
1066         uint16_t crc = 0xffff;
1067         for(int i = 0; i < am_size; i++) {
1068                 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xa1]);
1069         }
1070         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ 0xfe]);
1071         id[0] = t[0];
1072         id[1] = t[1];
1073         id[2] = t[2];
1074         id[3] = t[3];
1075         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
1076         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
1077         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
1078         crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
1079         id[4] = (crc >> 8) & 0xff;
1080         id[5] = (crc >> 0) & 0xff;
1081         // http://www.gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
1082         // t[6]: 0x00 = double-density, 0x40 = single-density
1083         // t[7]: 0x00 = normal, 0x10 = deleted mark
1084         // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
1085         density = t[6];
1086         deleted = (t[7] != 0);
1087 //      if(ignore_crc()) {
1088 //              addr_crc_error = false;
1089 //              data_crc_error = false;
1090 //      } else {
1091                 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
1092                 data_crc_error = ((t[8] & 0xf0) == 0xb0);
1093 //      }
1094         sector = t + 0x10;
1095         sector_size.read_2bytes_le_from(t + 14);
1096 }
1097
1098 void DISK::set_deleted(bool value)
1099 {
1100         if(sector != NULL) {
1101                 uint8_t *t = sector - 0x10;
1102                 t[7] = value ? 0x10 : 0;
1103                 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
1104                         t[8] = (t[8] & 0x0f) | t[7];
1105                 }
1106         }
1107         deleted = value;
1108 }
1109
1110 void DISK::set_data_crc_error(bool value)
1111 {
1112         if(sector != NULL) {
1113                 uint8_t *t = sector - 0x10;
1114                 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
1115         }
1116         data_crc_error = value;
1117 }
1118
1119 void DISK::set_data_mark_missing()
1120 {
1121         if(sector != NULL) {
1122                 uint8_t *t = sector - 0x10;
1123                 t[8] = (t[8] & 0x0f) | 0xf0;
1124                 t[14] = t[15] = 0;
1125         }
1126 //      addr_crc_error = false;
1127         data_crc_error = false;
1128 }
1129
1130 bool DISK::format_track(int trk, int side)
1131 {
1132         // disk not inserted or invalid media type
1133         if(!(inserted && check_media_type())) {
1134                 return false;
1135         }
1136         
1137         // search track
1138         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
1139         if(!(0 <= trkside && trkside < 164)) {
1140                 return false;
1141         }
1142         
1143         // create new empty track
1144         if(trim_required) {
1145                 trim_buffer();
1146                 trim_required = false;
1147         }
1148         memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
1149         pair_t offset;
1150         offset.d = DISK_BUFFER_SIZE;
1151         offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
1152         
1153         trim_required = true;
1154         sector_num.sd = 0;
1155         track_mfm = drive_mfm;
1156         
1157         return true;
1158 }
1159
1160 void DISK::insert_sector(uint8_t c, uint8_t h, uint8_t r, uint8_t n, bool deleted, bool data_crc_error, uint8_t fill_data, int length)
1161 {
1162         uint8_t* t = buffer + DISK_BUFFER_SIZE;
1163         
1164         sector_num.sd++;
1165         for(int i = 0; i < (sector_num.sd - 1); i++) {
1166                 t[4] = sector_num.b.l;
1167                 t[5] = sector_num.b.h;
1168                 pair_t data_size;
1169                 data_size.read_2bytes_le_from(t + 14);
1170                 t += data_size.sd + 0x10;
1171         }
1172         t[0] = c;
1173         t[1] = h;
1174         t[2] = r;
1175         t[3] = n;
1176         t[4] = sector_num.b.l;
1177         t[5] = sector_num.b.h;
1178         t[6] = track_mfm ? 0 : 0x40;
1179         t[7] = deleted ? 0x10 : 0;
1180         t[8] = data_crc_error ? 0xb0 : t[7];
1181         t[14] = (length >> 0) & 0xff;
1182         t[15] = (length >> 8) & 0xff;
1183         memset(t + 16, fill_data, length);
1184         
1185         set_sector_info(t);
1186 }
1187
1188 void DISK::sync_buffer()
1189 {
1190         if(trim_required) {
1191                 trim_buffer();
1192                 trim_required = false;
1193         }
1194 }
1195
1196 void DISK::trim_buffer()
1197 {
1198         int max_tracks = 164;
1199         int track_limit = 164;
1200         uint32_t dest_offset = 0x2b0;
1201         
1202         // copy header
1203         memset(tmp_buffer, 0, sizeof(tmp_buffer));
1204         memcpy(tmp_buffer, buffer, 0x20);
1205         
1206         // check max tracks
1207         if(media_type == MEDIA_TYPE_2D) {
1208                 track_limit = 84;
1209         }
1210         for(int trkside = 0; trkside < 164; trkside++) {
1211                 pair_t src_trk_offset;
1212                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1213                 if(src_trk_offset.d != 0) {
1214 #if 1
1215                         if(src_trk_offset.d < 0x2b0) {
1216                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1217                                 if(max_tracks > track_limit) {
1218                                         max_tracks = track_limit;
1219                                 }
1220                         }
1221 #else
1222                         if(src_trk_offset.d != 0x2b0) {
1223                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1224                                 if(max_tracks > 164) {
1225                                         dest_offset = 0x20 + max_tracks * 4);
1226                                 }
1227                         }
1228 #endif
1229                         break;
1230                 }
1231         }
1232         
1233         // copy tracks
1234         for(int trkside = 0; trkside < max_tracks; trkside++) {
1235                 pair_t src_trk_offset;
1236                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1237                 
1238                 pair_t dest_trk_offset;
1239                 dest_trk_offset.d = 0;
1240                 
1241                 if(IS_VALID_TRACK(src_trk_offset.d)) {
1242                         uint8_t* t = buffer + src_trk_offset.d;
1243                         pair_t sector_num, data_size;
1244                         sector_num.read_2bytes_le_from(t + 4);
1245                         if(sector_num.sd != 0) {
1246                                 dest_trk_offset.d = dest_offset;
1247                                 for(int i = 0; i < sector_num.sd; i++) {
1248                                         data_size.read_2bytes_le_from(t + 14);
1249                                         memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1250                                         dest_offset += data_size.sd + 0x10;
1251                                         t += data_size.sd + 0x10;
1252                                 }
1253                         }
1254                 }
1255                 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1256         }
1257         
1258         // update file size
1259         file_size.d = dest_offset;
1260         file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1261         
1262         memset(buffer, 0, sizeof(buffer));
1263         memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1264 }
1265
1266 int DISK::get_rpm()
1267 {
1268         if(drive_rpm != 0) {
1269                 return drive_rpm;
1270         } else if(inserted) {
1271                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1272         } else {
1273                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1274         }
1275 }
1276
1277 int DISK::get_track_size()
1278 {
1279         if(track_size != 0) {
1280                 return track_size;
1281         } else if(inserted) {
1282                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1283         } else {
1284                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1285         }
1286 }
1287
1288 double DISK::get_usec_per_track()
1289 {
1290         return 1000000.0 / (get_rpm() / 60.0);
1291 }
1292
1293 double DISK::get_usec_per_bytes(int bytes)
1294 {
1295         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1296 }
1297
1298 int DISK::get_bytes_per_usec(double usec)
1299 {
1300         return (int)(usec / get_usec_per_bytes(1) + 0.5);
1301 }
1302
1303 bool DISK::check_media_type()
1304 {
1305         switch(drive_type) {
1306         case DRIVE_TYPE_2D:
1307                 if(type_fm77av_2dd) {
1308                         return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1309                 } else {
1310                         return (media_type == MEDIA_TYPE_2D);
1311                 }
1312         case DRIVE_TYPE_2DD:
1313                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1314         case DRIVE_TYPE_2HD:
1315                 return (media_type == MEDIA_TYPE_2HD);
1316         case DRIVE_TYPE_144:
1317                 return (media_type == MEDIA_TYPE_144);
1318         case DRIVE_TYPE_UNK:
1319                 return true; // always okay
1320         }
1321         return false;
1322 }
1323
1324 // image decoder
1325
1326 #define COPYBUFFER(src, size) { \
1327         if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1328                 return false; \
1329         } \
1330         memcpy(buffer + file_size.d, (src), (size)); \
1331         file_size.d += (size); \
1332 }
1333
1334 typedef struct {
1335         char title[17];
1336         uint8_t rsrv[9];
1337         uint8_t protect;
1338         uint8_t type;
1339         uint32_t size;
1340         uint32_t trkptr[164];
1341 } d88_hdr_t;
1342
1343 typedef struct {
1344         uint8_t c, h, r, n;
1345         uint16_t nsec;
1346         uint8_t dens, del, stat;
1347         uint8_t rsrv[5];
1348         uint16_t size;
1349 } d88_sct_t;
1350
1351 // teledisk image decoder
1352
1353 /*
1354         this teledisk image decoder is based on:
1355         
1356                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1357                 LZSS coded by Haruhiko OKUMURA
1358                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1359                 Edited and translated to English by Kenji RIKITAKE
1360                 TDLZHUF.C by WTK
1361 */
1362
1363 #define STRING_BUFFER_SIZE      4096
1364 #define LOOKAHEAD_BUFFER_SIZE   60
1365 #define THRESHOLD               2
1366 #define N_CHAR                  (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1367 #define TABLE_SIZE              (N_CHAR * 2 - 1)
1368 #define ROOT_POSITION           (TABLE_SIZE - 1)
1369 #define MAX_FREQ                0x8000
1370
1371 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1372 static uint16_t td_ptr;
1373 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1374 static uint16_t td_ibufcnt, td_ibufndx;
1375 static uint8_t td_inbuf[512];
1376 static uint16_t td_freq[TABLE_SIZE + 1];
1377 static short td_prnt[TABLE_SIZE + N_CHAR];
1378 static short td_son[TABLE_SIZE];
1379 static uint16_t td_getbuf;
1380 static uint8_t td_getlen;
1381
1382 static const uint8_t td_d_code[256] = {
1383         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1384         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1385         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1386         0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1387         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1388         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1389         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1390         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1391         0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1392         0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1393         0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1394         0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1395         0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1396         0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1397         0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1398         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1399 };
1400 static const uint8_t td_d_len[256] = {
1401         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1402         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1403         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1404         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1405         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1406         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1407         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1408         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1409         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1410         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1411         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1412         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1413         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1414         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1415         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1416         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1417 };
1418
1419 static int td_next_word(FILEIO* fio)
1420 {
1421         if(td_ibufndx >= td_ibufcnt) {
1422                 td_ibufndx = td_ibufcnt = 0;
1423                 memset(td_inbuf, 0, 512);
1424                 for(int i = 0; i < 512; i++) {
1425                         int d = fio->Fgetc();
1426                         if(d == EOF) {
1427                                 if(i) {
1428                                         break;
1429                                 }
1430                                 return(-1);
1431                         }
1432                         td_inbuf[i] = d;
1433                         td_ibufcnt = i + 1;
1434                 }
1435         }
1436         while(td_getlen <= 8) {
1437                 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1438                 td_getlen += 8;
1439         }
1440         return 0;
1441 }
1442
1443 static int td_get_bit(FILEIO* fio)
1444 {
1445         if(td_next_word(fio) < 0) {
1446                 return -1;
1447         }
1448         short i = td_getbuf;
1449         td_getbuf <<= 1;
1450         td_getlen--;
1451         return (i < 0) ? 1 : 0;
1452 }
1453
1454 static int td_get_byte(FILEIO* fio)
1455 {
1456         if(td_next_word(fio) != 0) {
1457                 return -1;
1458         }
1459         uint16_t i = td_getbuf;
1460         td_getbuf <<= 8;
1461         td_getlen -= 8;
1462         i >>= 8;
1463         return (int)i;
1464 }
1465
1466 static void td_start_huff()
1467 {
1468         int i, j;
1469         for(i = 0; i < N_CHAR; i++) {
1470                 td_freq[i] = 1;
1471                 td_son[i] = i + TABLE_SIZE;
1472                 td_prnt[i + TABLE_SIZE] = i;
1473         }
1474         i = 0; j = N_CHAR;
1475         while(j <= ROOT_POSITION) {
1476                 td_freq[j] = td_freq[i] + td_freq[i + 1];
1477                 td_son[j] = i;
1478                 td_prnt[i] = td_prnt[i + 1] = j;
1479                 i += 2; j++;
1480         }
1481         td_freq[TABLE_SIZE] = 0xffff;
1482         td_prnt[ROOT_POSITION] = 0;
1483 }
1484
1485 static void td_reconst()
1486 {
1487         short i, j = 0, k;
1488         uint16_t f, l;
1489         for(i = 0; i < TABLE_SIZE; i++) {
1490                 if(td_son[i] >= TABLE_SIZE) {
1491                         td_freq[j] = (td_freq[i] + 1) / 2;
1492                         td_son[j] = td_son[i];
1493                         j++;
1494                 }
1495         }
1496         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1497                 k = i + 1;
1498                 f = td_freq[j] = td_freq[i] + td_freq[k];
1499                 for(k = j - 1; f < td_freq[k]; k--);
1500                 k++;
1501                 l = (j - k) * 2;
1502                 memmove(&td_freq[k + 1], &td_freq[k], l);
1503                 td_freq[k] = f;
1504                 memmove(&td_son[k + 1], &td_son[k], l);
1505                 td_son[k] = i;
1506         }
1507         for(i = 0; i < TABLE_SIZE; i++) {
1508                 if((k = td_son[i]) >= TABLE_SIZE) {
1509                         td_prnt[k] = i;
1510                 } else {
1511                         td_prnt[k] = td_prnt[k + 1] = i;
1512                 }
1513         }
1514 }
1515
1516 static void td_update(int c)
1517 {
1518         int i, j, k, l;
1519         if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1520                 td_reconst();
1521         }
1522         c = td_prnt[c + TABLE_SIZE];
1523         do {
1524                 k = ++td_freq[c];
1525                 if(k > td_freq[l = c + 1]) {
1526                         while(k > td_freq[++l]);
1527                         l--;
1528                         td_freq[c] = td_freq[l];
1529                         td_freq[l] = k;
1530                         i = td_son[c];
1531                         td_prnt[i] = l;
1532                         if(i < TABLE_SIZE) {
1533                                 td_prnt[i + 1] = l;
1534                         }
1535                         j = td_son[l];
1536                         td_son[l] = i;
1537                         td_prnt[j] = c;
1538                         if(j < TABLE_SIZE) {
1539                                 td_prnt[j + 1] = c;
1540                         }
1541                         td_son[c] = j;
1542                         c = l;
1543                 }
1544         }
1545         while((c = td_prnt[c]) != 0);
1546 }
1547
1548 static short td_decode_char(FILEIO* fio)
1549 {
1550         int ret;
1551         uint16_t c = td_son[ROOT_POSITION];
1552         while(c < TABLE_SIZE) {
1553                 if((ret = td_get_bit(fio)) < 0) {
1554                         return -1;
1555                 }
1556                 c += (unsigned)ret;
1557                 c = td_son[c];
1558         }
1559         c -= TABLE_SIZE;
1560         td_update(c);
1561         return c;
1562 }
1563
1564 static short td_decode_position(FILEIO* fio)
1565 {
1566         short bit;
1567         uint16_t i, j, c;
1568         if((bit = td_get_byte(fio)) < 0) {
1569                 return -1;
1570         }
1571         i = (uint16_t)bit;
1572         c = (uint16_t)td_d_code[i] << 6;
1573         j = td_d_len[i] - 2;
1574         while(j--) {
1575                 if((bit = td_get_bit(fio)) < 0) {
1576                          return -1;
1577                 }
1578                 i = (i << 1) + bit;
1579         }
1580         return (c | (i & 0x3f));
1581 }
1582
1583 static void td_init_decode()
1584 {
1585         td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1586         td_getlen = 0;
1587         td_start_huff();
1588         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1589                 td_text_buf[i] = ' ';
1590         }
1591         td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1592 }
1593
1594 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1595 {
1596         short c, pos;
1597         int  count;
1598         for(count = 0; count < len;) {
1599                 if(td_bufcnt == 0) {
1600                         if((c = td_decode_char(fio)) < 0) {
1601                                 return count;
1602                         }
1603                         if(c < 256) {
1604                                 *(buf++) = (uint8_t)c;
1605                                 td_text_buf[td_ptr++] = (uint8_t)c;
1606                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1607                                 count++;
1608                         } else {
1609                                 if((pos = td_decode_position(fio)) < 0) {
1610                                         return count;
1611                                 }
1612                                 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1613                                 td_bufcnt = c - 255 + THRESHOLD;
1614                                 td_bufndx = 0;
1615                         }
1616                 } else {
1617                         while(td_bufndx < td_bufcnt && count < len) {
1618                                 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1619                                 *(buf++) = (uint8_t)c;
1620                                 td_bufndx++;
1621                                 td_text_buf[td_ptr++] = (uint8_t)c;
1622                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1623                                 count++;
1624                         }
1625                         if(td_bufndx >= td_bufcnt) {
1626                                 td_bufndx = td_bufcnt = 0;
1627                         }
1628                 }
1629         }
1630         return count;
1631 }
1632
1633 typedef struct {
1634         char sig[3];
1635         uint8_t unknown;
1636         uint8_t ver;
1637         uint8_t dens;
1638         uint8_t type;
1639         uint8_t flag;
1640         uint8_t dos;
1641         uint8_t sides;
1642         uint16_t crc;
1643 } td_hdr_t;
1644
1645 typedef struct {
1646         uint16_t crc;
1647         uint16_t len;
1648         uint8_t ymd[3];
1649         uint8_t hms[3];
1650 } td_cmt_t;
1651
1652 typedef struct {
1653         uint8_t nsec, trk, head;
1654         uint8_t crc;
1655 } td_trk_t;
1656
1657 typedef struct {
1658         uint8_t c, h, r, n;
1659         uint8_t ctrl, crc;
1660 } td_sct_t;
1661
1662 bool DISK::teledisk_to_d88(FILEIO *fio)
1663 {
1664         td_hdr_t hdr;
1665         td_cmt_t cmt;
1666         td_trk_t trk;
1667         td_sct_t sct;
1668         uint8_t obuf[512];
1669         bool temporary = false;
1670         
1671         // check teledisk header
1672         fio->Fseek(0, FILEIO_SEEK_SET);
1673         fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1674         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1675                 // this image is compressed
1676                 // decompress to the temporary file
1677                 FILEIO* fio_tmp = new FILEIO();
1678                 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1679                         delete fio_tmp;
1680                         return false;
1681                 }
1682                 int rd = 1;
1683                 td_init_decode();
1684                 do {
1685                         if((rd = td_decode(fio, obuf, 512)) > 0) {
1686                                 fio_tmp->Fwrite(obuf, rd, 1);
1687                         }
1688                 }
1689                 while(rd > 0);
1690                 fio_tmp->Fclose();
1691                 delete fio_tmp;
1692                 temporary = true;
1693                 
1694                 // reopen the temporary file
1695                 fio->Fclose();
1696                 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1697                         return false;
1698                 }
1699         } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1700                 // this image is not compressed
1701         } else {
1702                 return false;
1703         }
1704         if(hdr.flag & 0x80) {
1705                 // skip comment
1706                 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1707                 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1708         }
1709         
1710         // create d88 header
1711         d88_hdr_t d88_hdr;
1712         d88_sct_t d88_sct;
1713         
1714         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1715         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1716         d88_hdr.protect = 0; // non-protected
1717         
1718         file_size.d = 0;
1719         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1720         
1721         // create tracks
1722         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1723         fio->Fread(&trk, sizeof(td_trk_t), 1);
1724         while(trk.nsec != 0xff) {
1725                 d88_hdr.trkptr[trkcnt++] = trkptr;
1726                 if(hdr.sides == 1) {
1727                         trkcnt++;
1728                 }
1729                 
1730                 // read sectors in this track
1731                 for(int i = 0; i < trk.nsec; i++) {
1732                         uint8_t buf[2048], dst[2048];
1733                         memset(buf, 0, sizeof(buf));
1734                         memset(dst, 0, sizeof(dst));
1735                         
1736                         // read sector header
1737                         fio->Fread(&sct, sizeof(td_sct_t), 1);
1738                         
1739                         // create d88 sector header
1740                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1741                         d88_sct.c = sct.c;
1742                         d88_sct.h = sct.h;
1743                         d88_sct.r = sct.r;
1744                         d88_sct.n = sct.n;
1745                         d88_sct.nsec = trk.nsec;
1746                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1747                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1748                         d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1749                         d88_sct.size = secsize[sct.n & 3];
1750                         
1751                         // create sector image
1752                         if(sct.ctrl & 0x30) {
1753                                 d88_sct.stat = 0xf0; // data mark missing
1754                                 d88_sct.size = 0;
1755                         } else {
1756                                 // read sector source
1757                                 int len = fio->Fgetc();
1758                                 len += fio->Fgetc() * 256 - 1;
1759                                 int flag = fio->Fgetc(), d = 0;
1760                                 fio->Fread(buf, len, 1);
1761                                 
1762                                 // convert
1763                                 if(flag == 0) {
1764                                         memcpy(dst, buf, len);
1765                                 } else if(flag == 1) {
1766                                         pair_t len2;
1767                                         len2.read_2bytes_le_from(buf);
1768                                         while(len2.sd--) {
1769                                                 dst[d++] = buf[2];
1770                                                 dst[d++] = buf[3];
1771                                         }
1772                                 } else if(flag == 2) {
1773                                         for(int s = 0; s < len;) {
1774                                                 int type = buf[s++];
1775                                                 int len2 = buf[s++];
1776                                                 if(type == 0) {
1777                                                         while(len2--) {
1778                                                                 dst[d++] = buf[s++];
1779                                                         }
1780                                                 } else if(type < 5) {
1781                                                         uint8_t pat[256];
1782                                                         int n = 2;
1783                                                         while(type-- > 1) {
1784                                                                 n *= 2;
1785                                                         }
1786                                                         for(int j = 0; j < n; j++) {
1787                                                                 pat[j] = buf[s++];
1788                                                         }
1789                                                         while(len2--) {
1790                                                                 for(int j = 0; j < n; j++) {
1791                                                                         dst[d++] = pat[j];
1792                                                                 }
1793                                                         }
1794                                                 } else {
1795                                                         break; // unknown type
1796                                                 }
1797                                         }
1798                                 } else {
1799                                         break; // unknown flag
1800                                 }
1801                         }
1802                         
1803                         // copy to d88
1804                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1805                         COPYBUFFER(dst, d88_sct.size);
1806                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1807                 }
1808                 // read next track
1809                 fio->Fread(&trk, sizeof(td_trk_t), 1);
1810         }
1811         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1812         d88_hdr.size = trkptr;
1813         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1814         
1815         if(temporary) {
1816                 FILEIO::RemoveFile(_T("teledisk.$$$"));
1817         }
1818         return true;
1819 }
1820
1821 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1822
1823 bool DISK::imagedisk_to_d88(FILEIO *fio)
1824 {
1825         int size = fio->FileLength();
1826         fio->Fseek(0, FILEIO_SEEK_SET);
1827         fio->Fread(tmp_buffer, size, 1);
1828         
1829         if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1830                 return false;
1831         }
1832         
1833         int pos;
1834         for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1835         pos++;
1836         
1837         if(pos >= size) {
1838                 return false;
1839         }
1840         
1841         // create d88 header
1842         d88_hdr_t d88_hdr;
1843         d88_sct_t d88_sct;
1844         
1845         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1846         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1847         d88_hdr.protect = 0; // non-protected
1848         
1849         file_size.d = 0;
1850         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1851         
1852         // create tracks
1853         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1854         int img_mode = -1;
1855         uint8_t dst[8192];
1856         
1857         while(pos < size) {
1858                 // check track header
1859                 uint8_t mode = tmp_buffer[pos++];
1860                 uint8_t track = tmp_buffer[pos++];
1861                 uint8_t head = tmp_buffer[pos++];
1862                 uint8_t sector_count = tmp_buffer[pos++];
1863                 uint8_t ssize = tmp_buffer[pos++];
1864                 
1865                 if(sector_count == 0) {
1866                         continue;
1867                 }
1868                 if(ssize == 0xff) {
1869                         return false;
1870                 }
1871                 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1872                 
1873                 // setup sector id
1874                 const uint8_t *snum = &tmp_buffer[pos];
1875                 pos += sector_count;
1876                 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1877                 if(tnum)
1878                         pos += sector_count;
1879                 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1880                 if(hnum)
1881                         pos += sector_count;
1882                 head &= 0x3f;
1883                 
1884                 // create new track
1885                 int trkside = track * 2 + (head & 1);
1886                 if(trkside < 164) {
1887                         if(trkcnt < trkside) {
1888                                 trkcnt = trkside;
1889                         }
1890                         d88_hdr.trkptr[trkside] = trkptr;
1891                 }
1892                 if(img_mode == -1) {
1893                         img_mode = mode & 3;
1894                 }
1895                 
1896                 // read sectors in this track
1897                 for(int i = 0; i < sector_count; i++) {
1898                         // create d88 sector header
1899                         uint8_t stype = tmp_buffer[pos++];
1900                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1901                         d88_sct.c = tnum ? tnum[i] : track;
1902                         d88_sct.h = hnum ? hnum[i] : head;
1903                         d88_sct.r = snum[i];
1904                         d88_sct.n = ssize;
1905                         d88_sct.nsec = sector_count;
1906                         d88_sct.dens = (mode < 3) ? 0x40 : 0;
1907                         
1908                         if(stype == 0 || stype > 8) {
1909                                 d88_sct.stat = 0xf0; // data mark missing
1910                                 d88_sct.size = 0;
1911                         } else {
1912                                 d88_sct.del  = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1913                                 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1914                                 d88_sct.size = actual_size;
1915                                 
1916                                 // create sector image
1917                                 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1918                                         memset(dst, tmp_buffer[pos++], actual_size);
1919                                 } else {
1920                                         memcpy(dst, &tmp_buffer[pos], actual_size);
1921                                         pos += d88_sct.size;
1922                                 }
1923                         }
1924                         
1925                         // copy to d88
1926                         if(trkside < 164) {
1927                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1928                                 COPYBUFFER(dst, d88_sct.size);
1929                                 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1930                         }
1931                 }
1932         }
1933         d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1934         d88_hdr.size = trkptr;
1935         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1936         return true;
1937 }
1938
1939 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1940
1941 #define DSK_FORMAT_HEADER       "MV - CPC"
1942 #define EXT_FORMAT_HEADER       "EXTENDED CPC DSK"
1943
1944 #pragma pack(1)
1945 struct track_header {
1946         uint8_t headertag[13];
1947         uint16_t unused1;
1948         uint8_t unused1b;
1949         uint8_t track_number;
1950         uint8_t side_number;
1951         uint8_t datarate;
1952         uint8_t rec_mode;
1953         uint8_t sector_size_code;
1954         uint8_t number_of_sector;
1955         uint8_t gap3_length;
1956         uint8_t filler_byte;
1957 };
1958 struct sector_header {
1959         uint8_t track;
1960         uint8_t side;
1961         uint8_t sector_id;
1962         uint8_t sector_size_code;
1963         uint8_t fdc_status_reg1;
1964         uint8_t fdc_status_reg2;
1965         uint16_t data_length;
1966 };
1967 #pragma pack()
1968
1969 bool DISK::cpdread_to_d88(FILEIO *fio)
1970 {
1971         bool extendformat = false;
1972         int image_size = fio->FileLength();
1973         
1974         fio->Fseek(0, FILEIO_SEEK_SET);
1975         fio->Fread(tmp_buffer, image_size, 1);
1976         
1977         if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1978                 extendformat = true;
1979         } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1980                 extendformat = false;
1981         } else {
1982                 return false;
1983         }
1984         
1985         int heads = tmp_buffer[0x31];
1986         int skip = 1;
1987         if(heads == 1) {
1988                 skip = 2;
1989         }
1990         int tracks = tmp_buffer[0x30];
1991         int track_offsets[84 * 2];
1992         bool track_offsets_error = false;
1993         if(!extendformat) {
1994                 int cnt = 0, tmp = 0x100;
1995                 for(int i = 0; i < tracks * heads; i++) {
1996                         track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
1997                         if(track_offsets_error) {
1998                                 break;
1999                         }
2000                         track_offsets[cnt] = tmp;
2001                         tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
2002                         cnt += skip;
2003                 }
2004         } else  {
2005                 int cnt = 0, tmp = 0x100;
2006                 for(int i = 0; i < tracks * heads; i++) {
2007                         int length = tmp_buffer[0x34 + i] << 8;
2008                         if(length != 0) {
2009                                 track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0);
2010                                 if(track_offsets_error) {
2011                                         break;
2012                                 }
2013                                 track_offsets[cnt] = tmp;
2014                                 tmp += length;
2015                         } else {
2016                                 track_offsets[cnt] = image_size;
2017                         }
2018                         cnt += skip;
2019                 }
2020         }
2021         if(track_offsets_error) {
2022                 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
2023                 // so I modified this code to search "Track-Info" at the top of track information block
2024                 int cnt = 0, tmp = 0x100;
2025                 for(int i = 0; i < tracks * heads; i++) {
2026                         bool found = false;
2027                         for(; tmp < image_size; tmp += 0x10) {
2028                                 found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0);
2029                                 if(found) {
2030                                         break;
2031                                 }
2032                         }
2033                         if(found) {
2034                                 track_offsets[cnt] = tmp;
2035                                 tmp += 0x10;
2036                         } else {
2037                                 track_offsets[cnt] = image_size;
2038                         }
2039                         cnt += skip;
2040                 }
2041         }
2042         
2043         // create d88 header
2044         d88_hdr_t d88_hdr;
2045         d88_sct_t d88_sct;
2046         
2047         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2048         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
2049         d88_hdr.protect = 0; // non-protected
2050         
2051         file_size.d = 0;
2052         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2053         
2054         // create tracks
2055         int total = 0, trkptr = sizeof(d88_hdr_t);
2056         
2057         for(int track = 0; track < tracks; track++) {
2058                 for(int side = 0; side < heads; side++) {
2059                         if(track_offsets[(track << 1) + side] >= image_size) {
2060                                 continue;
2061                         }
2062                         if((track << 1) + side < 164) {
2063                                 d88_hdr.trkptr[(track << 1) + side] = trkptr;
2064                         }
2065                         
2066                         track_header tr;
2067                         memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
2068                         int pos = track_offsets[(track << 1) + side] + 0x100;
2069                         for(int j = 0; j < tr.number_of_sector; j++) {
2070                                 sector_header sector;
2071                                 memcpy(&sector, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
2072                                 
2073                                 // create d88 sector header
2074                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2075                                 d88_sct.c = sector.track;
2076                                 d88_sct.h = sector.side;
2077                                 d88_sct.r = sector.sector_id;
2078                                 d88_sct.n = sector.sector_size_code;
2079                                 d88_sct.nsec = tr.number_of_sector;
2080                                 if(extendformat) {
2081                                         d88_sct.size = sector.data_length;
2082                                         d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
2083                                 } else {
2084                                         d88_sct.size = 128 << tr.sector_size_code;
2085                                         d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
2086                                 }
2087                                 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
2088                                 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
2089                                 
2090                                 // copy to d88
2091                                 if((track << 1) + side < 164) {
2092                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2093                                         COPYBUFFER(tmp_buffer + pos, d88_sct.size);
2094                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
2095                                 }
2096                                 total += d88_sct.size;
2097                                 
2098                                 if(extendformat) {
2099                                         pos += sector.data_length;
2100                                 } else {
2101                                         pos += 128 << tr.sector_size_code;
2102                                 }
2103                         }
2104                 }
2105         }
2106         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
2107         d88_hdr.size = trkptr;
2108         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2109         return true;
2110 }
2111
2112 // solid image decoder
2113
2114 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
2115 {
2116         int n = 0, t = 0;
2117         
2118         media_type = type;
2119         solid_ncyl = ncyl;
2120         solid_nside = nside;
2121         solid_nsec = nsec;
2122         solid_size = size;
2123         solid_mfm = mfm;
2124         
2125         // create d88 header
2126         d88_hdr_t d88_hdr;
2127         d88_sct_t d88_sct;
2128         
2129         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
2130         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
2131         d88_hdr.protect = 0; // non-protected
2132         
2133         file_size.d = 0;
2134         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
2135         
2136         // sector length
2137         for(int i = 0; i < 8; i++) {
2138                 if(size == (128 << i)) {
2139                         n = i;
2140                         break;
2141                 }
2142         }
2143         
2144         // create tracks
2145         int trkptr = sizeof(d88_hdr_t);
2146         
2147         for(int c = 0; c < ncyl; c++) {
2148                 for(int h = 0; h < nside; h++) {
2149                         d88_hdr.trkptr[t++] = trkptr;
2150                         if(nside == 1) {
2151                                 t++;
2152                         }
2153                         
2154                         // read sectors in this track
2155                         for(int s = 0; s < nsec; s++) {
2156                                 // create d88 sector header
2157                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
2158                                 d88_sct.c = c;
2159                                 d88_sct.h = h;
2160                                 d88_sct.r = s + 1;
2161                                 d88_sct.n = n;
2162                                 d88_sct.nsec = nsec;
2163                                 d88_sct.dens = 0;
2164                                 d88_sct.del = 0;
2165                                 d88_sct.stat = 0;
2166                                 d88_sct.size = size;
2167                                 
2168                                 // create sector image
2169                                 uint8_t dst[16384];
2170                                 memset(dst, 0xe5, sizeof(dst));
2171                                 fio->Fread(dst, size, 1);
2172                                 
2173                                 // copy to d88
2174                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2175                                 COPYBUFFER(dst, size);
2176                                 trkptr += sizeof(d88_sct_t) + size;
2177                         }
2178                 }
2179         }
2180         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2181         d88_hdr.size = trkptr;
2182         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2183         return true;
2184 }
2185
2186 #define STATE_VERSION   13
2187
2188 void DISK::save_state(FILEIO* state_fio)
2189 {
2190         state_fio->FputUint32(STATE_VERSION);
2191         
2192         state_fio->Fwrite(buffer, sizeof(buffer), 1);
2193         state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2194         state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2195         state_fio->FputUint32(file_size.d);
2196         state_fio->FputInt32(file_bank);
2197         state_fio->FputUint32(orig_file_size);
2198         state_fio->FputUint32(orig_crc32);
2199         state_fio->FputBool(trim_required);
2200         state_fio->FputBool(is_1dd_image);
2201         state_fio->FputBool(is_solid_image);
2202         state_fio->FputBool(is_fdi_image);
2203         state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2204         state_fio->FputInt32(solid_ncyl);
2205         state_fio->FputInt32(solid_nside);
2206         state_fio->FputInt32(solid_nsec);
2207         state_fio->FputInt32(solid_size);
2208         state_fio->FputBool(solid_mfm);
2209         state_fio->FputBool(inserted);
2210         state_fio->FputBool(ejected);
2211         state_fio->FputBool(write_protected);
2212         state_fio->FputBool(changed);
2213         state_fio->FputUint8(media_type);
2214         state_fio->FputInt32(is_special_disk);
2215         state_fio->Fwrite(track, sizeof(track), 1);
2216         state_fio->FputInt32(sector_num.sd);
2217         state_fio->FputBool(track_mfm);
2218         state_fio->FputBool(invalid_format);
2219 //      state_fio->FputBool(no_skew);
2220         state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2221         state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2222         state_fio->Fwrite(id_position, sizeof(id_position), 1);
2223         state_fio->Fwrite(data_position, sizeof(data_position), 1);
2224 //      state_fio->FputInt32(gap3_size);
2225         state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2226         state_fio->FputInt32(sector_size.sd);
2227         state_fio->Fwrite(id, sizeof(id), 1);
2228         state_fio->FputUint8(density);
2229         state_fio->FputBool(deleted);
2230         state_fio->FputBool(addr_crc_error);
2231         state_fio->FputBool(data_crc_error);
2232         state_fio->FputUint8(drive_type);
2233         state_fio->FputInt32(drive_rpm);
2234         state_fio->FputBool(drive_mfm);
2235 }
2236
2237 bool DISK::load_state(FILEIO* state_fio)
2238 {
2239         if(state_fio->FgetUint32() != STATE_VERSION) {
2240                 return false;
2241         }
2242         state_fio->Fread(buffer, sizeof(buffer), 1);
2243         state_fio->Fread(orig_path, sizeof(orig_path), 1);
2244         state_fio->Fread(dest_path, sizeof(dest_path), 1);
2245         file_size.d = state_fio->FgetUint32();
2246         file_bank = state_fio->FgetInt32();
2247         orig_file_size = state_fio->FgetUint32();
2248         orig_crc32 = state_fio->FgetUint32();
2249         trim_required = state_fio->FgetBool();
2250         is_1dd_image = state_fio->FgetBool();
2251         is_solid_image = state_fio->FgetBool();
2252         is_fdi_image = state_fio->FgetBool();
2253         state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2254         solid_ncyl = state_fio->FgetInt32();
2255         solid_nside = state_fio->FgetInt32();
2256         solid_nsec = state_fio->FgetInt32();
2257         solid_size = state_fio->FgetInt32();
2258         solid_mfm = state_fio->FgetBool();
2259         inserted = state_fio->FgetBool();
2260         ejected = state_fio->FgetBool();
2261         write_protected = state_fio->FgetBool();
2262         changed = state_fio->FgetBool();
2263         media_type = state_fio->FgetUint8();
2264         is_special_disk = state_fio->FgetInt32();
2265         state_fio->Fread(track, sizeof(track), 1);
2266         sector_num.sd = state_fio->FgetInt32();
2267         track_mfm = state_fio->FgetBool();
2268         invalid_format = state_fio->FgetBool();
2269 //      no_skew = state_fio->FgetBool();
2270         state_fio->Fread(sync_position, sizeof(sync_position), 1);
2271         state_fio->Fread(am1_position, sizeof(am1_position), 1);
2272         state_fio->Fread(id_position, sizeof(id_position), 1);
2273         state_fio->Fread(data_position, sizeof(data_position), 1);
2274 //      gap3_size = state_fio->FgetInt32();
2275         int offset = state_fio->FgetInt32();
2276         sector = (offset != -1) ? buffer + offset : NULL;
2277         sector_size.sd = state_fio->FgetInt32();
2278         state_fio->Fread(id, sizeof(id), 1);
2279         density = state_fio->FgetUint8();
2280         deleted = state_fio->FgetBool();
2281         addr_crc_error = state_fio->FgetBool();
2282         data_crc_error = state_fio->FgetBool();
2283         drive_type = state_fio->FgetUint8();
2284         drive_rpm = state_fio->FgetInt32();
2285         drive_mfm = state_fio->FgetBool();
2286         return true;
2287 }
2288