OSDN Git Service

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