OSDN Git Service

[VM][General] Merge upstream 2016-02-13. Still don't implement OSD/Gui part of joysti...
[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 #include "disk.h"
11 #include "../fileio.h"
12
13 #ifndef _ANY2D88
14 #define local_path(x) create_local_path(x)
15 #else
16 #define local_path(x) (x)
17 #endif
18
19 // crc table
20 static const uint16 crc_table[256] = {
21         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
22         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
23         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
24         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
25         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
26         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
27         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
28         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
29         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
30         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
31         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
32         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
33         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
34         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
35         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
36         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
37 };
38
39 static const int secsize[8] = {
40         128, 256, 512, 1024, 2048, 4096, 8192, 16384
41 };
42
43 static uint8 tmp_buffer[DISK_BUFFER_SIZE];
44
45 // physical format table for solid image
46 typedef struct {
47         int type;
48         int ncyl, nside, nsec, size;
49         bool mfm;
50 } fd_format_t;
51
52 #define FM      false
53 #define MFM     true
54
55 static const fd_format_t fd_formats[] = {
56 #if defined(_SC3000)
57         { MEDIA_TYPE_2D,  40, 1, 16,  256, MFM },       // 1D   160KB
58 #elif defined(_SMC70) || defined(_SMC777)
59         { MEDIA_TYPE_2DD, 70, 1, 16,  256, MFM },       // 1DD  280KB
60 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
61         { MEDIA_TYPE_2D,  40, 2, 16,  256, MFM },       // 2D   320KB
62 #elif defined(_M5)
63         { MEDIA_TYPE_2D,  40, 2, 18,  256, MFM },       // 2D   360KB
64 #elif defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
65         { MEDIA_TYPE_2DD, 80, 2, 16,  256, MFM },       // 2DD  640KB
66 #endif
67         { MEDIA_TYPE_2D,  35, 1, 16,  128, FM  },       // 1S   70KB
68         { MEDIA_TYPE_2D,  35, 2, 16,  128, FM  },       // 2S   140KB
69         { MEDIA_TYPE_2DD, 77, 1, 26,  128, FM  },       // 1S   250KB
70         { MEDIA_TYPE_2D,  40, 1,  8,  512, MFM },       // 1D   160KB
71         { MEDIA_TYPE_2D,  40, 1,  9,  512, MFM },       // 1D   180KB
72         { MEDIA_TYPE_2D,  40, 1, 10,  512, MFM },       // 1D   200KB
73 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
74 //      { MEDIA_TYPE_2DD, 70, 1,  8,  512, MFM },       // 1DD  280KB
75 //      { MEDIA_TYPE_2DD, 70, 1,  9,  512, MFM },       // 1DD  315KB
76 //      { MEDIA_TYPE_2DD, 70, 1, 10,  512, MFM },       // 1DD  350KB
77 //      { MEDIA_TYPE_2DD, 80, 1,  8,  512, MFM },       // 1DD  320KB
78 //      { MEDIA_TYPE_2DD, 80, 1,  9,  512, MFM },       // 1DD  360KB
79 //      { MEDIA_TYPE_2DD, 80, 1, 10,  512, MFM },       // 1DD  400KB
80 //#else
81         { MEDIA_TYPE_2D,  35, 2,  8,  512, MFM },       // 2D   280KB
82         { MEDIA_TYPE_2D,  35, 2,  9,  512, MFM },       // 2D   315KB
83         { MEDIA_TYPE_2D,  35, 2, 10,  512, MFM },       // 2D   350KB
84         { MEDIA_TYPE_2D,  40, 2,  8,  512, MFM },       // 2D   320KB
85         { MEDIA_TYPE_2D,  40, 2,  9,  512, MFM },       // 2D   360KB
86         { MEDIA_TYPE_2D,  40, 2, 10,  512, MFM },       // 2D   400KB
87 //#endif
88         { MEDIA_TYPE_2DD, 80, 2,  8,  512, MFM },       // 2DD  640KB
89         { MEDIA_TYPE_2DD, 80, 2,  9,  512, MFM },       // 2DD  720KB
90         { MEDIA_TYPE_2DD, 81, 2,  9,  512, MFM },       // 2DD  729KB, ASCII MSX
91         { MEDIA_TYPE_2DD, 80, 2, 10,  512, MFM },       // 2DD  800KB
92         { MEDIA_TYPE_2HD, 77, 2, 26,  256, MFM },       // 2HD  1001KB, MITSUBISHI/IBM
93         { MEDIA_TYPE_2HD, 80, 2, 15,  512, MFM },       // 2HC  1200KB, TOSHIBA/IBM
94         { MEDIA_TYPE_2HD, 77, 2,  8, 1024, MFM },       // 2HD  1232KB, NEC
95         { MEDIA_TYPE_144, 80, 2, 18,  512, MFM },       // 2HD  1440KB
96         { MEDIA_TYPE_144, 80, 2, 21,  512, MFM },       // 2HD  1680KB
97         { MEDIA_TYPE_144, 82, 2, 21,  512, MFM },       // 2HD  1722KB
98         { MEDIA_TYPE_144, 80, 2, 36,  512, MFM },       // 2ED  2880KB
99         { -1, 0, 0, 0, 0 },
100 };
101
102 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
103
104 void DISK::open(const _TCHAR* file_path, int bank)
105 {
106         // check current disk image
107         if(inserted) {
108                 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
109                         return;
110                 }
111                 close();
112         }
113         if(bank < 0) {
114                 return;
115         }
116         memset(buffer, 0, sizeof(buffer));
117         file_bank = 0;
118         write_protected = false;
119         media_type = MEDIA_TYPE_UNK;
120         is_special_disk = 0;
121         is_solid_image = is_fdi_image = is_1dd_image = false;
122         trim_required = false;
123         track_mfm = drive_mfm;
124         
125         // open disk image
126         FILEIO *fio = new FILEIO();
127         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
128                 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
129                 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
130                 
131                 file_size.d = fio->FileLength();
132                 fio->Fseek(0, FILEIO_SEEK_SET);
133                 
134                 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
135                         // d88 image
136                         uint32 offset = 0;
137                         for(int i = 0; i < bank; i++) {
138                                 fio->Fseek(offset + 0x1c, SEEK_SET);
139                                 offset += fio->FgetUint32_LE();
140                         }
141                         fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
142                         file_size.d = fio->FgetUint32_LE();
143                         fio->Fseek(offset, FILEIO_SEEK_SET);
144                         fio->Fread(buffer, file_size.d, 1);
145                         file_bank = bank;
146                         if(check_file_extension(file_path, _T(".1dd"))) {
147                                 is_1dd_image = true;
148                                 media_type = MEDIA_TYPE_2DD;
149                         }
150                         inserted = changed = true;
151 //                      trim_required = true;
152                         
153                         // fix sector number from big endian to little endian
154                         for(int trkside = 0; trkside < 164; trkside++) {
155                                 pair offset;
156                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
157                                 
158                                 if(!IS_VALID_TRACK(offset.d)) {
159                                         break;
160                                 }
161                                 uint8* t = buffer + offset.d;
162                                 pair sector_num, data_size;
163                                 sector_num.read_2bytes_le_from(t + 4);
164                                 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
165                                 if(is_be) {
166                                         sector_num.read_2bytes_be_from(t + 4);
167                                         sector_num.write_2bytes_le_to(t + 4);
168                                 }
169                                 for(int i = 0; i < sector_num.sd; i++) {
170                                         if(is_be) {
171                                                 sector_num.write_2bytes_le_to(t + 4);
172                                         }
173                                         data_size.read_2bytes_le_from(t + 14);
174                                         t += data_size.sd + 0x10;
175                                 }
176                         }
177                 } else if(check_file_extension(file_path, _T(".td0"))) {
178                         // teledisk image
179                         try {
180                                 inserted = changed = teledisk_to_d88(fio);
181                                 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
182                         } catch(...) {
183                                 // failed to convert the disk image
184                         }
185                 } else if(check_file_extension(file_path, _T(".imd"))) {
186                         // imagedisk image
187                         try {
188                                 inserted = changed = imagedisk_to_d88(fio);
189                                 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
190                         } catch(...) {
191                                 // failed to convert the disk image
192                         }
193                 } else if(check_file_extension(file_path, _T(".dsk"))) {
194                         // cpdread image
195                         try {
196                                 inserted = changed = cpdread_to_d88(fio);
197                                 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
198                         } catch(...) {
199                                 // failed to convert the disk image
200                         }
201                 } else if(check_file_extension(file_path, _T(".2d"))  && file_size.d == 40 * 2 * 16 * 256) {
202                         // 2d image for SHARP X1 series
203                         inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true);
204                 } else if(check_file_extension(file_path, _T(".img"))  && file_size.d == 70 * 1 * 16 * 256) {
205                         // img image for SONY SMC-70/777 series
206                         inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true);
207                 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
208                         // sf7 image for SEGA SC-3000 + SF-7000
209                         inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true);
210                 }
211                 if(!inserted) {
212                         // check solid image file format
213                         bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
214                         for(int i = 0;; i++) {
215                                 const fd_format_t *p = &fd_formats[i];
216                                 if(p->type == -1) {
217                                         break;
218                                 }
219                                 int len = p->ncyl * p->nside * p->nsec * p->size;
220                                 // 4096 bytes: FDI header ???
221                                 if(file_size.d == len + (is_fdi_tmp ? 4096 : 0)) {
222                                         fio->Fseek(0, FILEIO_SEEK_SET);
223                                         if(is_fdi_tmp) {
224                                                 is_fdi_image = true;
225                                                 fio->Fread(fdi_header, 4096, 1);
226                                         }
227                                         int type = p->type;
228                                         int ncyl = p->ncyl;
229                                         int nside = p->nside;
230                                         int nsec = p->nsec;
231                                         int size = p->size;
232 #if defined(SUPPORT_MEDIA_TYPE_1DD)
233                                         if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
234                                                 type = MEDIA_TYPE_2DD;
235                                                 nside = 1;
236                                                 ncyl *= 2;
237                                         }
238 #elif defined(_ANY2D88)
239                                         if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
240                                                 type = MEDIA_TYPE_2DD;
241                                                 nside = 1;
242                                                 ncyl *= 2;
243                                         }
244                                         if(open_as_256 && (size == 512 || size == 1024)) {
245                                                 nsec *= size / 256;
246                                                 size = 256;
247                                         }
248 #endif
249 //                                      if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
250                                         if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
251                                                 inserted = changed = is_solid_image = true;
252                                                 break;
253                                         }
254                                 }
255                         }
256                 }
257                 if(fio->IsOpened()) {
258                         fio->Fclose();
259                 }
260         }
261         delete fio;
262         
263         // check loaded image
264         if(inserted) {
265                 // check media type
266                 if(media_type == MEDIA_TYPE_UNK) {
267                         if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
268                                 // check 1.2MB or 1.44MB
269                                 for(int trkside = 0; trkside < 164; trkside++) {
270                                         pair offset;
271                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
272                                         
273                                         if(!IS_VALID_TRACK(offset.d)) {
274                                                 continue;
275                                         }
276                                         // track found
277                                         uint8 *t = buffer + offset.d;
278                                         pair sector_num, data_size;
279                                         sector_num.read_2bytes_le_from(t + 4);
280                                         data_size.read_2bytes_le_from(t + 14);
281                                         
282                                         if(sector_num.sd >= 18 && data_size.sd == 512) {
283                                                 media_type = MEDIA_TYPE_144;
284                                         }
285                                         break;
286                                 }
287                         }
288                 }
289                 
290                 // fix write protect flag
291                 if(buffer[0x1a] != 0) {
292                         buffer[0x1a] = 0x10;
293                         write_protected = true;
294                 }
295                 
296                 // get crc32 for midification check
297                 crc32 = getcrc32(buffer, file_size.d);
298                 
299                 // check special disk image
300 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
301                 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
302                 if(media_type == MEDIA_TYPE_2D) {
303                         // check first track
304                         pair offset, sector_num, data_size;
305                         offset.read_4bytes_le_from(buffer + 0x20);
306                         if(IS_VALID_TRACK(offset.d)) {
307                                 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
308                                 uint8* t = buffer + offset.d;
309                                 sector_num.read_2bytes_le_from(t + 4);
310                                 for(int i = 0; i < sector_num.sd; i++) {
311                                         data_size.read_2bytes_le_from(t + 14);
312                                         if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
313                                                 static const uint8 gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
314                                                 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
315                                                         is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
316                                                         break;
317                                                 }
318                                         } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
319                                                 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
320                                                 static const uint8 deathforce[] ={
321                                                         0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
322                                                         0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
323                                                         0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
324                                                         0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
325                                                         0x00, 0x00
326                                                 };
327                                                 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
328                                                         is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
329                                                         break;
330                                                 }
331                                         } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
332                                                 //$03 + $2D + "PSY-O-BLADE   Copyright 1988 by T&E SOFT Inc" + $B6 + $FD + $05
333                                                 static const uint8 psyoblade_ipl1[] ={
334                                                         0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
335                                                         0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
336                                                         0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
337                                                         0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
338                                                         0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
339                                                         0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
340                                                         0xfd, 0x05
341                                                 };
342                                                 //IPL Signature1
343                                                 static const uint8 psyoblade_disk_1[] ={
344                                                         0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
345                                                         0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
346                                                         0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
347                                                         0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
348                                                 };
349                                                 //$00 + $00 + $03 + $14 + "PSY-O-BLADE  DISK" + $B6 + $FD + $05
350                                                 static const uint8 psyoblade_disk_2[] ={
351                                                         0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
352                                                         0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
353                                                         0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
354                                                 };
355                                                 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
356                                                         is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
357                                                         break;
358                                                 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
359                                                         if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
360                                                                 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
361                                                                 break;
362                                                         }
363                                                 }
364                                         }
365                                         t += data_size.sd + 0x10;
366                                 }
367                         }
368                 }
369 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
370                 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
371                 if(media_type == MEDIA_TYPE_2D) {
372                         // check first track
373                         pair offset;
374                         offset.read_4bytes_le_from(buffer + 0x20);
375                         if(IS_VALID_TRACK(offset.d)) {
376                                 // check first sector
377                                 static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
378                                 uint8 *t = buffer + offset.d;
379 #if defined(_X1TURBO) || defined(_X1TURBOZ)
380 //                              if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
381 //                                      is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
382 //                              } else
383 #endif
384                                 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
385                                         is_special_disk = SPECIAL_DISK_X1_BATTEN;
386                                 }
387                         }
388                 }
389 #endif
390         }
391 }
392
393 void DISK::close()
394 {
395         // write disk image
396         if(inserted) {
397                 if(trim_required) {
398                         trim_buffer();
399                         trim_required = false;
400                 }
401                 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
402                 
403                 if(/*!write_protected &&*/ file_size.d && getcrc32(buffer, file_size.d) != crc32) {
404                         // write image
405                         FILEIO* fio = new FILEIO();
406                         int pre_size = 0, post_size = 0;
407                         uint8 *pre_buffer = NULL, *post_buffer = NULL;
408                         
409                         // is this d88 format ?
410                         if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
411                                 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
412                                         fio->Fseek(0, FILEIO_SEEK_END);
413                                         uint32 total_size = fio->Ftell(), offset = 0;
414                                         for(int i = 0; i < file_bank; i++) {
415                                                 fio->Fseek(offset + 0x1c, SEEK_SET);
416                                                 offset += fio->FgetUint32_LE();
417                                         }
418                                         if((pre_size = offset) > 0) {
419                                                 pre_buffer = (uint8 *)malloc(pre_size);
420                                                 fio->Fseek(0, FILEIO_SEEK_SET);
421                                                 fio->Fread(pre_buffer, pre_size, 1);
422                                         }
423                                         fio->Fseek(offset + 0x1c, SEEK_SET);
424                                         offset += fio->FgetUint32_LE();
425                                         if((post_size = total_size - offset) > 0) {
426                                                 post_buffer = (uint8 *)malloc(post_size);
427                                                 fio->Fseek(offset, FILEIO_SEEK_SET);
428                                                 fio->Fread(post_buffer, post_size, 1);
429                                         }
430                                         fio->Fclose();
431                                 }
432                         }
433                         
434                         // is this solid image and was physical formatted ?
435                         if(is_solid_image) {
436                                 bool formatted = false;
437                                 int tracks = 0;
438                                 
439                                 for(int trkside = 0; trkside < 164; trkside++) {
440                                         pair offset;
441                                         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
442                                         
443                                         if(!IS_VALID_TRACK(offset.d)) {
444                                                 continue;
445                                         }
446                                         if(solid_nside == 1 && (trkside & 1) == 1) {
447                                                 formatted = true;
448                                         }
449                                         tracks++;
450                                         
451                                         uint8* t = buffer + offset.d;
452                                         pair sector_num, data_size;
453                                         sector_num.read_2bytes_le_from(t + 4);
454                                         
455                                         if(sector_num.sd != solid_nsec) {
456                                                 formatted = true;
457                                         }
458                                         for(int i = 0; i < sector_num.sd; i++) {
459                                                 data_size.read_2bytes_le_from(t + 14);
460                                                 if(data_size.sd != solid_size) {
461                                                         formatted = true;
462                                                 }
463                                                 if(t[6] != (solid_mfm ? 0 : 0x40)) {
464                                                         formatted = true;
465                                                 }
466                                                 t += data_size.sd + 0x10;
467                                         }
468                                 }
469                                 if(tracks != (solid_ncyl * solid_nside)) {
470                                         formatted = true;
471                                 }
472                                 if(formatted) {
473                                         my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
474                                         is_solid_image = false;
475                                 }
476                         }
477                         
478                         if((FILEIO::IsFileExists(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
479                                 _TCHAR tmp_path[_MAX_PATH];
480                                 my_stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
481                                 fio->Fopen(local_path(tmp_path), FILEIO_WRITE_BINARY);
482                         }
483                         if(fio->IsOpened()) {
484                                 if(pre_buffer) {
485                                         fio->Fwrite(pre_buffer, pre_size, 1);
486                                 }
487                                 if(is_solid_image) {
488                                         if(is_fdi_image) {
489                                                 fio->Fwrite(fdi_header, 4096, 1);
490                                         }
491                                         for(int trkside = 0; trkside < 164; trkside++) {
492                                                 pair offset;
493                                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
494                                                 
495                                                 if(!IS_VALID_TRACK(offset.d)) {
496                                                         continue;
497                                                 }
498                                                 uint8* t = buffer + offset.d;
499                                                 pair sector_num, data_size;
500                                                 sector_num.read_2bytes_le_from(t + 4);
501                                                 
502                                                 for(int i = 0; i < sector_num.sd; i++) {
503                                                         data_size.read_2bytes_le_from(t + 14);
504                                                         fio->Fwrite(t + 0x10, data_size.sd, 1);
505                                                         t += data_size.sd + 0x10;
506                                                 }
507                                         }
508                                 } else {
509                                         fio->Fwrite(buffer, file_size.d, 1);
510                                 }
511                                 if(post_buffer) {
512                                         fio->Fwrite(post_buffer, post_size, 1);
513                                 }
514                                 fio->Fclose();
515                         }
516                         if(pre_buffer) {
517                                 free(pre_buffer);
518                         }
519                         if(post_buffer) {
520                                 free(post_buffer);
521                         }
522                         delete fio;
523                 }
524                 ejected = true;
525         }
526         inserted = write_protected = false;
527         file_size.d = 0;
528         sector_size.sd = sector_num.sd = 0;
529         sector = NULL;
530 }
531
532 #ifdef _ANY2D88
533 void DISK::save_as_d88(const _TCHAR* file_path)
534 {
535         if(inserted) {
536                 FILEIO* fio = new FILEIO();
537                 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
538                         if(is_1dd_image) {
539                                 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
540                                 for(int trk = 0; trk < 82; trk++) {
541                                         memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
542                                         memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
543                                 }
544                                 buffer[0x1b] = MEDIA_TYPE_2DD;
545                         }
546                         fio->Fwrite(buffer, file_size.d, 1);
547                         fio->Fclose();
548                 }
549                 delete fio;
550         }
551 }
552 #endif
553
554 bool DISK::get_track(int trk, int side)
555 {
556         sector_size.sd = sector_num.sd = 0;
557         invalid_format = false;
558 //      no_skew = true;
559
560         // disk not inserted or invalid media type
561         if(!(inserted && check_media_type())) {
562                 return false;
563         }
564
565         // search track
566         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
567         if(!(0 <= trkside && trkside < 164)) {
568                 return false;
569         }
570         cur_track = trk;
571         cur_side = side;
572         
573         pair offset;
574         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
575         
576         if(!IS_VALID_TRACK(offset.d)) {
577                 return false;
578         }
579         
580         // track found
581         sector = buffer + offset.d;
582         sector_num.read_2bytes_le_from(sector + 4);
583         pair data_size;
584         data_size.read_2bytes_le_from(sector + 14);
585         
586         // create each sector position in track
587         track_mfm = false;
588         if(sector_num.sd == 0) {
589                 track_mfm = drive_mfm;
590         } else {
591                 uint8* t = sector;
592                 for(int i = 0; i < sector_num.sd; i++) {
593                         data_size.read_2bytes_le_from(t + 14);
594                         // t[6]: 0x00 = double-density, 0x40 = single-density
595                         if(t[6] == 0x00) {
596                                 track_mfm = true;
597                                 break;
598                         }
599                         t += data_size.sd + 0x10;
600                 }
601         }
602         int sync_size  = track_mfm ? 12 : 6;
603         int am_size = track_mfm ? 3 : 0;
604         int gap0_size = track_mfm ? 80 : 40;
605         int gap1_size = track_mfm ? 50 : 26;
606         int gap2_size = track_mfm ? 22 : 11;
607 //      int gap3_size = 0, gap4_size;
608         gap3_size = 0;
609         int gap4_size;
610         
611         if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
612                 if(track_mfm) {
613                         if(data_size.sd ==  256 && sector_num.sd == 26) gap3_size =  54;
614                         if(data_size.sd ==  512 && sector_num.sd == 15) gap3_size =  84;
615                         if(data_size.sd == 1024 && sector_num.sd ==  8) gap3_size = 116;
616                 } else {
617                         if(data_size.sd ==  128 && sector_num.sd == 26) gap3_size =  27;
618                         if(data_size.sd ==  256 && sector_num.sd == 15) gap3_size =  42;
619                         if(data_size.sd ==  512 && sector_num.sd ==  8) gap3_size =  58;
620                 }
621         } else {
622                 if(track_mfm) {
623                         if(data_size.sd ==  256 && sector_num.sd == 16) gap3_size =  51;
624                         if(data_size.sd ==  512 && sector_num.sd ==  9) gap3_size =  80;
625                         if(data_size.sd == 1024 && sector_num.sd ==  5) gap3_size = 116;
626                 } else {
627                         if(data_size.sd ==  128 && sector_num.sd == 16) gap3_size =  27;
628                         if(data_size.sd ==  256 && sector_num.sd ==  9) gap3_size =  42;
629                         if(data_size.sd ==  512 && sector_num.sd ==  5) gap3_size =  58;
630                 }
631         }
632         
633         uint8* t = sector;
634         int total = 0, valid_sector_num = 0;
635         
636         for(int i = 0; i < sector_num.sd; i++) {
637                 data_size.read_2bytes_le_from(t + 14);
638                 sync_position[i] = total; // for invalid format case
639                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
640                 if(data_size.sd > 0) {
641                         total += sync_size + (am_size + 1);
642                         total += data_size.sd + 2;
643                         valid_sector_num++;
644                 }
645 //              if(t[2] != i + 1) {
646 //                      no_skew = false;
647 //              }
648                 t += data_size.sd + 0x10;
649         }
650         total += sync_size + (am_size + 1); // sync in preamble
651         
652         if(gap3_size == 0) {
653                 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
654         }
655         gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
656         
657         if(gap3_size < 8 || gap4_size < 8) {
658                 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
659                 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
660         }
661         if(gap3_size < 8 || gap4_size < 8) {
662                 gap0_size = gap1_size = gap3_size = gap4_size = 8;
663                 invalid_format = true;
664         }
665         int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
666         
667         if(invalid_format) {
668                 total -= sync_size + (am_size + 1);
669                 for(int i = 0; i < sector_num.sd; i++) {
670                         sync_position[i] *= get_track_size() - preamble_size - gap4_size;
671                         sync_position[i] /= total;
672                 }
673         }
674         t = sector;
675         total = preamble_size;
676         sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
677         
678         for(int i = 0; i < sector_num.sd; i++) {
679                 data_size.read_2bytes_le_from(t + 14);
680                 if(invalid_format) {
681                         total = preamble_size + sync_position[i];
682                 }
683                 sync_position[i] = total;
684                 total += sync_size;
685                 am1_position[i] = total;
686                 total += am_size + 1;
687                 id_position[i] = total;
688                 total += (4 + 2) + gap2_size;
689                 if(data_size.sd > 0) {
690                         total += sync_size + (am_size + 1);
691                         data_position[i] = total;
692                         total += data_size.sd + 2;
693                         total += gap3_size;
694                 } else {
695                         data_position[i] = total; // FIXME
696                 }
697                 t += data_size.sd + 0x10;
698         }
699         return true;
700 }
701
702 bool DISK::make_track(int trk, int side)
703 {
704         int track_size = get_track_size();
705         
706         if(!get_track(trk, side)) {
707                 // create a dummy track
708                 for(int i = 0; i < track_size; i++) {
709                         track[i] = rand();
710                 }
711                 return false;
712         }
713         
714         // make track image
715         int sync_size  = track_mfm ? 12 : 6;
716         int am_size = track_mfm ? 3 : 0;
717         int gap2_size = track_mfm ? 22 : 11;
718         uint8 gap_data = track_mfm ? 0x4e : 0xff;
719         
720         // preamble
721         memset(track, gap_data, track_size);
722         int q = sync_position[array_length(sync_position) - 1];
723         
724         // sync
725         for(int i = 0; i < sync_size; i++) {
726                 track[q++] = 0x00;
727         }
728         // index mark
729         for(int i = 0; i < am_size; i++) {
730                 track[q++] = 0xc2;
731         }
732         track[q++] = 0xfc;
733         
734         // sectors
735         uint8 *t = sector;
736         
737         for(int i = 0; i < sector_num.sd; i++) {
738                 pair data_size;
739                 data_size.read_2bytes_le_from(t + 14);
740                 int p = sync_position[i];
741                 
742                 // sync
743                 for(int j = 0; j < sync_size; j++) {
744                         if(p < track_size) track[p++] = 0x00;
745                 }
746                 // am1
747                 for(int j = 0; j < am_size; j++) {
748                         if(p < track_size) track[p++] = 0xa1;
749                 }
750                 if(p < track_size) track[p++] = 0xfe;
751                 // id
752                 if(p < track_size) track[p++] = t[0];
753                 if(p < track_size) track[p++] = t[1];
754                 if(p < track_size) track[p++] = t[2];
755                 if(p < track_size) track[p++] = t[3];
756                 uint16 crc = 0;
757                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
758                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
759                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
760                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
761                 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
762                 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
763                 // gap2
764                 for(int j = 0; j < gap2_size; j++) {
765                         if(p < track_size) track[p++] = gap_data;
766                 }
767                 // data field
768                 if(data_size.sd > 0) {
769                         // sync
770                         for(int j = 0; j < sync_size; j++) {
771                                 if(p < track_size) track[p++] = 0x00;
772                         }
773                         // am2
774                         for(int j = 0; j < am_size; j++) {
775                                 if(p < track_size) track[p++] = 0xa1;
776                         }
777                         if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
778                         // data
779                         crc = 0;
780                         for(int j = 0; j < data_size.sd; j++) {
781                                 if(p < track_size) track[p++] = t[0x10 + j];
782                                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
783                         }
784                         if(p < track_size) track[p++] = (crc >> 8) & 0xff;
785                         if(p < track_size) track[p++] = (crc >> 0) & 0xff;
786                 }
787                 t += data_size.sd + 0x10;
788         }
789         return true;
790 }
791
792 bool DISK::get_sector(int trk, int side, int index)
793 {
794         sector_size.sd = sector_num.sd = 0;
795         sector = NULL;
796         
797         // disk not inserted or invalid media type
798         if(!(inserted && check_media_type())) {
799                 return false;
800         }
801
802         // search track
803         if(trk == -1 && side == -1) {
804                 trk = cur_track;
805                 side = cur_side;
806         }
807         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
808         if(!(0 <= trkside && trkside < 164)) {
809                 return false;
810         }
811         pair offset;
812         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
813         
814         if(!IS_VALID_TRACK(offset.d)) {
815                 return false;
816         }
817         
818         // track found
819         uint8* t = buffer + offset.d;
820         sector_num.read_2bytes_le_from(t + 4);
821         
822         if(index >= sector_num.sd) {
823                 return false;
824         }
825         
826         // skip sector
827         for(int i = 0; i < index; i++) {
828                 pair data_size;
829                 data_size.read_2bytes_le_from(t + 14);
830                 t += data_size.sd + 0x10;
831         }
832         set_sector_info(t);
833         return true;
834 }
835
836 void DISK::set_sector_info(uint8 *t)
837 {
838         // header info
839         id[0] = t[0];
840         id[1] = t[1];
841         id[2] = t[2];
842         id[3] = t[3];
843         uint16 crc = 0;
844         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
845         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
846         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
847         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
848         id[4] = (crc >> 8) & 0xff;
849         id[5] = (crc >> 0) & 0xff;
850         // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
851         // t[6]: 0x00 = double-density, 0x40 = single-density
852         // t[7]: 0x00 = normal, 0x10 = deleted mark
853         // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
854         density = t[6];
855         deleted = (t[7] != 0);
856    
857 //      if(ignore_crc()) {
858 //              addr_crc_error = false;
859 //              data_crc_error = false;
860 //      } else {
861                 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
862                 data_crc_error = ((t[8] & 0xf0) == 0xb0);
863 //      }
864         sector = t + 0x10;
865         sector_size.read_2bytes_le_from(t + 14);
866 }
867
868 void DISK::set_deleted(bool value)
869 {
870         if(sector != NULL) {
871                 uint8 *t = sector - 0x10;
872                 t[7] = value ? 0x10 : 0;
873                 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
874                         t[8] = (t[8] & 0x0f) | t[7];
875                 }
876         }
877         deleted = value;
878 }
879
880 void DISK::set_data_crc_error(bool value)
881 {
882         if(sector != NULL) {
883                 uint8 *t = sector - 0x10;
884                 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
885         }
886         data_crc_error = value;
887 }
888
889 void DISK::set_data_mark_missing()
890 {
891         if(sector != NULL) {
892                 uint8 *t = sector - 0x10;
893                 t[8] = (t[8] & 0x0f) | 0xf0;
894                 t[14] = t[15] = 0;
895
896         }
897         //addr_crc_error = false;
898         data_crc_error = false;
899 }
900
901 bool DISK::format_track(int trk, int side)
902 {
903         // disk not inserted or invalid media type
904         if(!(inserted && check_media_type())) {
905                 return false;
906         }
907         
908         // search track
909         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
910         if(!(0 <= trkside && trkside < 164)) {
911                 return false;
912         }
913         
914         // create new empty track
915         if(trim_required) {
916                 trim_buffer();
917                 trim_required = false;
918         }
919         memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
920         pair offset;
921         offset.d = DISK_BUFFER_SIZE;
922         offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
923         
924         trim_required = true;
925         sector_num.sd = 0;
926         track_mfm = drive_mfm;
927         
928         return true;
929 }
930
931 void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool data_crc_error, uint8 fill_data, int length)
932 {
933         uint8* t = buffer + DISK_BUFFER_SIZE;
934         
935         sector_num.sd++;
936         for(int i = 0; i < (sector_num.sd - 1); i++) {
937                 t[4] = sector_num.b.l;
938                 t[5] = sector_num.b.h;
939                 pair data_size;
940                 data_size.read_2bytes_le_from(t + 14);
941                 t += data_size.sd + 0x10;
942         }
943         t[0] = c;
944         t[1] = h;
945         t[2] = r;
946         t[3] = n;
947         t[4] = sector_num.b.l;
948         t[5] = sector_num.b.h;
949         t[6] = track_mfm ? 0 : 0x40;
950         t[7] = deleted ? 0x10 : 0;
951         t[8] = data_crc_error ? 0xb0 : t[7];
952         t[14] = (length >> 0) & 0xff;
953         t[15] = (length >> 8) & 0xff;
954         memset(t + 16, fill_data, length);
955         
956         set_sector_info(t);
957 }
958
959 void DISK::sync_buffer()
960 {
961         if(trim_required) {
962                 trim_buffer();
963                 trim_required = false;
964         }
965 }
966
967 void DISK::trim_buffer()
968 {
969         int max_tracks = 164;
970         uint32 dest_offset = 0x2b0;
971         
972         // copy header
973         memset(tmp_buffer, 0, sizeof(tmp_buffer));
974         memcpy(tmp_buffer, buffer, 0x20);
975         
976         // check max tracks
977         for(int trkside = 0; trkside < 164; trkside++) {
978                 pair src_trk_offset;
979                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
980                 if(src_trk_offset.d != 0) {
981 #if 1
982                         if(src_trk_offset.d < 0x2b0) {
983                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
984                         }
985 #else
986                         if(src_trk_offset.d != 0x2b0) {
987                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
988                                 if(max_tracks > 164) {
989                                         dest_offset = 0x20 + max_tracks * 4);
990                                 }
991                         }
992 #endif
993                         break;
994                 }
995         }
996         
997         // copy tracks
998         for(int trkside = 0; trkside < max_tracks; trkside++) {
999                 pair src_trk_offset;
1000                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1001                 
1002                 pair dest_trk_offset;
1003                 dest_trk_offset.d = 0;
1004                 
1005                 if(IS_VALID_TRACK(src_trk_offset.d)) {
1006                         uint8* t = buffer + src_trk_offset.d;
1007                         pair sector_num, data_size;
1008                         sector_num.read_2bytes_le_from(t + 4);
1009                         if(sector_num.sd != 0) {
1010                                 dest_trk_offset.d = dest_offset;
1011                                 for(int i = 0; i < sector_num.sd; i++) {
1012                                         data_size.read_2bytes_le_from(t + 14);
1013                                         memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1014                                         dest_offset += data_size.sd + 0x10;
1015                                         t += data_size.sd + 0x10;
1016                                 }
1017                         }
1018                 }
1019                 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1020         }
1021         
1022         // update file size
1023         file_size.d = dest_offset;
1024         file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1025         
1026         memset(buffer, 0, sizeof(buffer));
1027 //      memcpy(buffer, tmp_buffer, file_size.d);
1028         memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1029         //memcpy(buffer, tmp_buffer, (file_size.d > sizeof(buffer)) ? sizeof(buffer) : file_size.d);
1030 }
1031
1032 int DISK::get_rpm()
1033 {
1034         if(drive_rpm != 0) {
1035                 return drive_rpm;
1036         } else if(inserted) {
1037                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1038         } else {
1039                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1040         }
1041 }
1042
1043 int DISK::get_track_size()
1044 {
1045         if(inserted) {
1046 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
1047                 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
1048                         //return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3500;
1049                         return 6300;
1050                 }
1051 #endif
1052                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1053         } else {
1054                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1055         }
1056 }
1057
1058 double DISK::get_usec_per_track()
1059 {
1060         return 1000000.0 / (get_rpm() / 60.0);
1061 }
1062
1063 double DISK::get_usec_per_bytes(int bytes)
1064 {
1065 #if defined(_FM77AV_VARIANTS)
1066         if(is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) {
1067                 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0) * 2.2) * bytes;
1068         }
1069 #endif
1070         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1071 }
1072
1073 int DISK::get_bytes_per_usec(double usec)
1074 {
1075         return (int)(usec / get_usec_per_bytes(1) + 0.5);
1076 }
1077
1078 bool DISK::check_media_type()
1079 {
1080         switch(drive_type) {
1081         case DRIVE_TYPE_2D:
1082 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1083         defined(_FM77AV20) || defined(_FM77AV20EX)
1084                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1085 #else           
1086                 return (media_type == MEDIA_TYPE_2D);
1087 #endif          
1088         case DRIVE_TYPE_2DD:
1089                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1090         case DRIVE_TYPE_2HD:
1091                 return (media_type == MEDIA_TYPE_2HD);
1092         case DRIVE_TYPE_144:
1093                 return (media_type == MEDIA_TYPE_144);
1094         case DRIVE_TYPE_UNK:
1095                 return true; // always okay
1096         }
1097         return false;
1098 }
1099
1100 // image decoder
1101
1102 #define COPYBUFFER(src, size) { \
1103         if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1104                 return false; \
1105         } \
1106         memcpy(buffer + file_size.d, (src), (size)); \
1107         file_size.d += (size); \
1108 }
1109
1110 typedef struct {
1111         char title[17];
1112         uint8 rsrv[9];
1113         uint8 protect;
1114         uint8 type;
1115         uint32 size;
1116         uint32 trkptr[164];
1117 } d88_hdr_t;
1118
1119 typedef struct {
1120         uint8 c, h, r, n;
1121         uint16 nsec;
1122         uint8 dens, del, stat;
1123         uint8 rsrv[5];
1124         uint16 size;
1125 } d88_sct_t;
1126
1127 // teledisk image decoder
1128
1129 /*
1130         this teledisk image decoder is based on:
1131         
1132                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1133                 LZSS coded by Haruhiko OKUMURA
1134                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1135                 Edited and translated to English by Kenji RIKITAKE
1136                 TDLZHUF.C by WTK
1137 */
1138
1139 #define STRING_BUFFER_SIZE      4096
1140 #define LOOKAHEAD_BUFFER_SIZE   60
1141 #define THRESHOLD               2
1142 #define N_CHAR                  (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1143 #define TABLE_SIZE              (N_CHAR * 2 - 1)
1144 #define ROOT_POSITION           (TABLE_SIZE - 1)
1145 #define MAX_FREQ                0x8000
1146
1147 static uint8 td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1148 static uint16 td_ptr;
1149 static uint16 td_bufcnt, td_bufndx, td_bufpos;
1150 static uint16 td_ibufcnt, td_ibufndx;
1151 static uint8 td_inbuf[512];
1152 static uint16 td_freq[TABLE_SIZE + 1];
1153 static short td_prnt[TABLE_SIZE + N_CHAR];
1154 static short td_son[TABLE_SIZE];
1155 static uint16 td_getbuf;
1156 static uint8 td_getlen;
1157
1158 static const uint8 td_d_code[256] = {
1159         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1160         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1161         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1162         0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1163         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1164         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1165         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1166         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1167         0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1168         0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1169         0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1170         0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1171         0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1172         0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1173         0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1174         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1175 };
1176 static const uint8 td_d_len[256] = {
1177         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1178         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1179         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1180         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1181         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1182         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1183         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1184         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1185         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1186         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1187         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1188         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1189         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1190         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1191         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1192         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1193 };
1194
1195 static int td_next_word(FILEIO* fio)
1196 {
1197         if(td_ibufndx >= td_ibufcnt) {
1198                 td_ibufndx = td_ibufcnt = 0;
1199                 memset(td_inbuf, 0, 512);
1200                 for(int i = 0; i < 512; i++) {
1201                         int d = fio->Fgetc();
1202                         if(d == EOF) {
1203                                 if(i) {
1204                                         break;
1205                                 }
1206                                 return(-1);
1207                         }
1208                         td_inbuf[i] = d;
1209                         td_ibufcnt = i + 1;
1210                 }
1211         }
1212         while(td_getlen <= 8) {
1213                 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1214                 td_getlen += 8;
1215         }
1216         return 0;
1217 }
1218
1219 static int td_get_bit(FILEIO* fio)
1220 {
1221         if(td_next_word(fio) < 0) {
1222                 return -1;
1223         }
1224         short i = td_getbuf;
1225         td_getbuf <<= 1;
1226         td_getlen--;
1227         return (i < 0) ? 1 : 0;
1228 }
1229
1230 static int td_get_byte(FILEIO* fio)
1231 {
1232         if(td_next_word(fio) != 0) {
1233                 return -1;
1234         }
1235         uint16 i = td_getbuf;
1236         td_getbuf <<= 8;
1237         td_getlen -= 8;
1238         i >>= 8;
1239         return (int)i;
1240 }
1241
1242 static void td_start_huff()
1243 {
1244         int i, j;
1245         for(i = 0; i < N_CHAR; i++) {
1246                 td_freq[i] = 1;
1247                 td_son[i] = i + TABLE_SIZE;
1248                 td_prnt[i + TABLE_SIZE] = i;
1249         }
1250         i = 0; j = N_CHAR;
1251         while(j <= ROOT_POSITION) {
1252                 td_freq[j] = td_freq[i] + td_freq[i + 1];
1253                 td_son[j] = i;
1254                 td_prnt[i] = td_prnt[i + 1] = j;
1255                 i += 2; j++;
1256         }
1257         td_freq[TABLE_SIZE] = 0xffff;
1258         td_prnt[ROOT_POSITION] = 0;
1259 }
1260
1261 static void td_reconst()
1262 {
1263         short i, j = 0, k;
1264         uint16 f, l;
1265         for(i = 0; i < TABLE_SIZE; i++) {
1266                 if(td_son[i] >= TABLE_SIZE) {
1267                         td_freq[j] = (td_freq[i] + 1) / 2;
1268                         td_son[j] = td_son[i];
1269                         j++;
1270                 }
1271         }
1272         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1273                 k = i + 1;
1274                 f = td_freq[j] = td_freq[i] + td_freq[k];
1275                 for(k = j - 1; f < td_freq[k]; k--);
1276                 k++;
1277                 l = (j - k) * 2;
1278                 memmove(&td_freq[k + 1], &td_freq[k], l);
1279                 td_freq[k] = f;
1280                 memmove(&td_son[k + 1], &td_son[k], l);
1281                 td_son[k] = i;
1282         }
1283         for(i = 0; i < TABLE_SIZE; i++) {
1284                 if((k = td_son[i]) >= TABLE_SIZE) {
1285                         td_prnt[k] = i;
1286                 } else {
1287                         td_prnt[k] = td_prnt[k + 1] = i;
1288                 }
1289         }
1290 }
1291
1292 static void td_update(int c)
1293 {
1294         int i, j, k, l;
1295         if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1296                 td_reconst();
1297         }
1298         c = td_prnt[c + TABLE_SIZE];
1299         do {
1300                 k = ++td_freq[c];
1301                 if(k > td_freq[l = c + 1]) {
1302                         while(k > td_freq[++l]);
1303                         l--;
1304                         td_freq[c] = td_freq[l];
1305                         td_freq[l] = k;
1306                         i = td_son[c];
1307                         td_prnt[i] = l;
1308                         if(i < TABLE_SIZE) {
1309                                 td_prnt[i + 1] = l;
1310                         }
1311                         j = td_son[l];
1312                         td_son[l] = i;
1313                         td_prnt[j] = c;
1314                         if(j < TABLE_SIZE) {
1315                                 td_prnt[j + 1] = c;
1316                         }
1317                         td_son[c] = j;
1318                         c = l;
1319                 }
1320         }
1321         while((c = td_prnt[c]) != 0);
1322 }
1323
1324 static short td_decode_char(FILEIO* fio)
1325 {
1326         int ret;
1327         uint16 c = td_son[ROOT_POSITION];
1328         while(c < TABLE_SIZE) {
1329                 if((ret = td_get_bit(fio)) < 0) {
1330                         return -1;
1331                 }
1332                 c += (unsigned)ret;
1333                 c = td_son[c];
1334         }
1335         c -= TABLE_SIZE;
1336         td_update(c);
1337         return c;
1338 }
1339
1340 static short td_decode_position(FILEIO* fio)
1341 {
1342         short bit;
1343         uint16 i, j, c;
1344         if((bit = td_get_byte(fio)) < 0) {
1345                 return -1;
1346         }
1347         i = (uint16)bit;
1348         c = (uint16)td_d_code[i] << 6;
1349         j = td_d_len[i] - 2;
1350         while(j--) {
1351                 if((bit = td_get_bit(fio)) < 0) {
1352                          return -1;
1353                 }
1354                 i = (i << 1) + bit;
1355         }
1356         return (c | i & 0x3f);
1357 }
1358
1359 static void td_init_decode()
1360 {
1361         td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1362         td_getlen = 0;
1363         td_start_huff();
1364         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1365                 td_text_buf[i] = ' ';
1366         }
1367         td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1368 }
1369
1370 static int td_decode(FILEIO* fio, uint8 *buf, int len)
1371 {
1372         short c, pos;
1373         int  count;
1374         for(count = 0; count < len;) {
1375                 if(td_bufcnt == 0) {
1376                         if((c = td_decode_char(fio)) < 0) {
1377                                 return count;
1378                         }
1379                         if(c < 256) {
1380                                 *(buf++) = (uint8)c;
1381                                 td_text_buf[td_ptr++] = (uint8)c;
1382                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1383                                 count++;
1384                         } else {
1385                                 if((pos = td_decode_position(fio)) < 0) {
1386                                         return count;
1387                                 }
1388                                 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1389                                 td_bufcnt = c - 255 + THRESHOLD;
1390                                 td_bufndx = 0;
1391                         }
1392                 } else {
1393                         while(td_bufndx < td_bufcnt && count < len) {
1394                                 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1395                                 *(buf++) = (uint8)c;
1396                                 td_bufndx++;
1397                                 td_text_buf[td_ptr++] = (uint8)c;
1398                                 td_ptr &= (STRING_BUFFER_SIZE - 1);
1399                                 count++;
1400                         }
1401                         if(td_bufndx >= td_bufcnt) {
1402                                 td_bufndx = td_bufcnt = 0;
1403                         }
1404                 }
1405         }
1406         return count;
1407 }
1408
1409 typedef struct {
1410         char sig[3];
1411         uint8 unknown;
1412         uint8 ver;
1413         uint8 dens;
1414         uint8 type;
1415         uint8 flag;
1416         uint8 dos;
1417         uint8 sides;
1418         uint16 crc;
1419 } td_hdr_t;
1420
1421 typedef struct {
1422         uint16 crc;
1423         uint16 len;
1424         uint8 ymd[3];
1425         uint8 hms[3];
1426 } td_cmt_t;
1427
1428 typedef struct {
1429         uint8 nsec, trk, head;
1430         uint8 crc;
1431 } td_trk_t;
1432
1433 typedef struct {
1434         uint8 c, h, r, n;
1435         uint8 ctrl, crc;
1436 } td_sct_t;
1437
1438 bool DISK::teledisk_to_d88(FILEIO *fio)
1439 {
1440         td_hdr_t hdr;
1441         td_cmt_t cmt;
1442         td_trk_t trk;
1443         td_sct_t sct;
1444         uint8 obuf[512];
1445         bool temporary = false;
1446         
1447         // check teledisk header
1448         fio->Fseek(0, FILEIO_SEEK_SET);
1449         fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1450         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1451                 // this image is compressed
1452                 // decompress to the temporary file
1453                 FILEIO* fio_tmp = new FILEIO();
1454                 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1455                         delete fio_tmp;
1456                         return false;
1457                 }
1458                 int rd = 1;
1459                 td_init_decode();
1460                 do {
1461                         if((rd = td_decode(fio, obuf, 512)) > 0) {
1462                                 fio_tmp->Fwrite(obuf, rd, 1);
1463                         }
1464                 }
1465                 while(rd > 0);
1466                 fio_tmp->Fclose();
1467                 delete fio_tmp;
1468                 temporary = true;
1469                 
1470                 // reopen the temporary file
1471                 fio->Fclose();
1472                 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1473                         return false;
1474                 }
1475         } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1476                 // this image is not compressed
1477         } else {
1478                 return false;
1479         }
1480         if(hdr.flag & 0x80) {
1481                 // skip comment
1482                 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1483                 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1484         }
1485         
1486         // create d88 header
1487         d88_hdr_t d88_hdr;
1488         d88_sct_t d88_sct;
1489         
1490         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1491         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1492         d88_hdr.protect = 0; // non-protected
1493         
1494         file_size.d = 0;
1495         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1496         
1497         // create tracks
1498         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1499         fio->Fread(&trk, sizeof(td_trk_t), 1);
1500         while(trk.nsec != 0xff) {
1501                 d88_hdr.trkptr[trkcnt++] = trkptr;
1502                 if(hdr.sides == 1) {
1503                         trkcnt++;
1504                 }
1505                 
1506                 // read sectors in this track
1507                 for(int i = 0; i < trk.nsec; i++) {
1508                         uint8 buf[2048], dst[2048];
1509                         memset(buf, 0, sizeof(buf));
1510                         memset(dst, 0, sizeof(dst));
1511                         
1512                         // read sector header
1513                         fio->Fread(&sct, sizeof(td_sct_t), 1);
1514                         
1515                         // create d88 sector header
1516                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1517                         d88_sct.c = sct.c;
1518                         d88_sct.h = sct.h;
1519                         d88_sct.r = sct.r;
1520                         d88_sct.n = sct.n;
1521                         d88_sct.nsec = trk.nsec;
1522                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1523                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1524                         d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1525                         d88_sct.size = secsize[sct.n & 3];
1526                         
1527                         // create sector image
1528                         if(sct.ctrl & 0x30) {
1529                                 d88_sct.stat = 0xf0; // data mark missing
1530                                 d88_sct.size = 0;
1531                         } else {
1532                                 // read sector source
1533                                 int len = fio->Fgetc();
1534                                 len += fio->Fgetc() * 256 - 1;
1535                                 int flag = fio->Fgetc(), d = 0;
1536                                 fio->Fread(buf, len, 1);
1537                                 
1538                                 // convert
1539                                 if(flag == 0) {
1540                                         memcpy(dst, buf, len);
1541                                 } else if(flag == 1) {
1542                                         pair len2;
1543                                         len2.read_2bytes_le_from(buf);
1544                                         while(len2.sd--) {
1545                                                 dst[d++] = buf[2];
1546                                                 dst[d++] = buf[3];
1547                                         }
1548                                 } else if(flag == 2) {
1549                                         for(int s = 0; s < len;) {
1550                                                 int type = buf[s++];
1551                                                 int len2 = buf[s++];
1552                                                 if(type == 0) {
1553                                                         while(len2--) {
1554                                                                 dst[d++] = buf[s++];
1555                                                         }
1556                                                 } else if(type < 5) {
1557                                                         uint8 pat[256];
1558                                                         int n = 2;
1559                                                         while(type-- > 1) {
1560                                                                 n *= 2;
1561                                                         }
1562                                                         for(int j = 0; j < n; j++) {
1563                                                                 pat[j] = buf[s++];
1564                                                         }
1565                                                         while(len2--) {
1566                                                                 for(int j = 0; j < n; j++) {
1567                                                                         dst[d++] = pat[j];
1568                                                                 }
1569                                                         }
1570                                                 } else {
1571                                                         break; // unknown type
1572                                                 }
1573                                         }
1574                                 } else {
1575                                         break; // unknown flag
1576                                 }
1577                         }
1578                         
1579                         // copy to d88
1580                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1581                         COPYBUFFER(dst, d88_sct.size);
1582                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1583                 }
1584                 // read next track
1585                 fio->Fread(&trk, sizeof(td_trk_t), 1);
1586         }
1587         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1588         d88_hdr.size = trkptr;
1589         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1590         
1591         if(temporary) {
1592                 FILEIO::RemoveFile(_T("teledisk.$$$"));
1593         }
1594         return true;
1595 }
1596
1597 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1598
1599 bool DISK::imagedisk_to_d88(FILEIO *fio)
1600 {
1601         int size = fio->FileLength();
1602         fio->Fseek(0, FILEIO_SEEK_SET);
1603         fio->Fread(tmp_buffer, size, 1);
1604
1605         if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1606                 return false;
1607         }
1608
1609         int pos;
1610         for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1611         pos++;
1612         
1613         if(pos >= size) {
1614                 return false;
1615         }
1616         
1617         // create d88 header
1618         d88_hdr_t d88_hdr;
1619         d88_sct_t d88_sct;
1620         
1621         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1622         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1623         d88_hdr.protect = 0; // non-protected
1624         
1625         file_size.d = 0;
1626         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1627         
1628         // create tracks
1629         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1630         int img_mode = -1;
1631         uint8 dst[8192];
1632         
1633         while(pos < size) {
1634                 // check track header
1635                 uint8 mode = tmp_buffer[pos++];
1636                 uint8 track = tmp_buffer[pos++];
1637                 uint8 head = tmp_buffer[pos++];
1638                 uint8 sector_count = tmp_buffer[pos++];
1639                 uint8 ssize = tmp_buffer[pos++];
1640                 
1641                 if(sector_count == 0) {
1642                         continue;
1643                 }
1644                 if(ssize == 0xff) {
1645                         return false;
1646                 }
1647                 uint32 actual_size = ssize < 7 ? 128 << ssize : 8192;
1648                 
1649                 // setup sector id
1650                 const uint8 *snum = &tmp_buffer[pos];
1651                 pos += sector_count;
1652                 const uint8 *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1653                 if(tnum)
1654                         pos += sector_count;
1655                 const uint8 *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1656                 if(hnum)
1657                         pos += sector_count;
1658                 head &= 0x3f;
1659                 
1660                 // create new track
1661                 int trkside = track * 2 + (head & 1);
1662                 if(trkside < 164) {
1663                         if(trkcnt < trkside) {
1664                                 trkcnt = trkside;
1665                         }
1666                         d88_hdr.trkptr[trkside] = trkptr;
1667                 }
1668                 if(img_mode == -1) {
1669                         img_mode = mode & 3;
1670                 }
1671                 
1672                 // read sectors in this track
1673                 for(int i = 0; i < sector_count; i++) {
1674                         // create d88 sector header
1675                         uint8 stype = tmp_buffer[pos++];
1676                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1677                         d88_sct.c = tnum ? tnum[i] : track;
1678                         d88_sct.h = hnum ? hnum[i] : head;
1679                         d88_sct.r = snum[i];
1680                         d88_sct.n = ssize;
1681                         d88_sct.nsec = sector_count;
1682                         d88_sct.dens = (mode < 3) ? 0x40 : 0;
1683                         
1684                         if(stype == 0 || stype > 8) {
1685                                 d88_sct.stat = 0xf0; // data mark missing
1686                                 d88_sct.size = 0;
1687                         } else {
1688                                 d88_sct.del  = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1689                                 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1690                                 d88_sct.size = actual_size;
1691                                 
1692                                 // create sector image
1693                                 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1694                                         memset(dst, tmp_buffer[pos++], actual_size);
1695                                 } else {
1696                                         memcpy(dst, &tmp_buffer[pos], actual_size);
1697                                         pos += d88_sct.size;
1698                                 }
1699                         }
1700                         
1701                         // copy to d88
1702                         if(trkside < 164) {
1703                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1704                                 COPYBUFFER(dst, d88_sct.size);
1705                                 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1706                         }
1707                 }
1708         }
1709         d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1710         d88_hdr.size = trkptr;
1711         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1712         return true;
1713 }
1714
1715 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1716
1717 #define DSK_FORMAT_HEADER       "MV - CPC"
1718 #define EXT_FORMAT_HEADER       "EXTENDED CPC DSK"
1719
1720 #pragma pack(1)
1721 struct track_header {
1722         uint8 headertag[13];
1723         uint16 unused1;
1724         uint8 unused1b;
1725         uint8 track_number;
1726         uint8 side_number;
1727         uint8 datarate;
1728         uint8 rec_mode;
1729         uint8 sector_size_code;
1730         uint8 number_of_sector;
1731         uint8 gap3_length;
1732         uint8 filler_byte;
1733 };
1734 struct sector_header {
1735         uint8 track;
1736         uint8 side;
1737         uint8 sector_id;
1738         uint8 sector_size_code;
1739         uint8 fdc_status_reg1;
1740         uint8 fdc_status_reg2;
1741         uint16 data_length;
1742 };
1743 #pragma pack()
1744
1745 bool DISK::cpdread_to_d88(FILEIO *fio)
1746 {
1747         bool extendformat = false;
1748         int image_size = fio->FileLength();
1749         
1750         fio->Fseek(0, FILEIO_SEEK_SET);
1751         fio->Fread(tmp_buffer, image_size, 1);
1752         
1753         if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1754                 extendformat = true;
1755         } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1756                 extendformat = false;
1757         } else {
1758                 return false;
1759         }
1760         
1761         int heads = tmp_buffer[0x31];
1762         int skip = 1;
1763         if(heads == 1) {
1764                 skip = 2;
1765         }
1766         int tracks = tmp_buffer[0x30];
1767         int track_offsets[84 * 2];
1768         bool track_offsets_error = false;
1769         if(!extendformat) {
1770                 int cnt = 0, tmp = 0x100;
1771                 for(int i = 0; i < tracks * heads; i++) {
1772                         if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1773                                 break;
1774                         }
1775                         track_offsets[cnt] = tmp;
1776                         tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1777                         cnt += skip;
1778                 }
1779         } else  {
1780                 int cnt = 0, tmp = 0x100;
1781                 for(int i = 0; i < tracks * heads; i++) {
1782                         int length = tmp_buffer[0x34 + i] << 8;
1783                         if(length != 0) {
1784                                 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1785                                         break;
1786                                 }
1787                                 track_offsets[cnt] = tmp;
1788                                 tmp += length;
1789                         } else {
1790                                 track_offsets[cnt] = image_size;
1791                         }
1792                         cnt += skip;
1793                 }
1794         }
1795         if(track_offsets_error) {
1796                 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1797                 // so I modified this code to search "Track-Info" at the top of track information block
1798                 int cnt = 0, tmp = 0x100;
1799                 for(int i = 0; i < tracks * heads; i++) {
1800                         bool found = false;
1801                         for(; tmp < image_size; tmp += 0x10) {
1802                                 if(found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0)) {
1803                                         break;
1804                                 }
1805                         }
1806                         if(found) {
1807                                 track_offsets[cnt] = tmp;
1808                                 tmp += 0x10;
1809                         } else {
1810                                 track_offsets[cnt] = image_size;
1811                         }
1812                         cnt += skip;
1813                 }
1814         }
1815         
1816         // create d88 header
1817         d88_hdr_t d88_hdr;
1818         d88_sct_t d88_sct;
1819         
1820         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1821         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
1822         d88_hdr.protect = 0; // non-protected
1823         
1824         file_size.d = 0;
1825         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1826         
1827         // create tracks
1828         int total = 0, trkptr = sizeof(d88_hdr_t);
1829         
1830         for(int track = 0; track < tracks; track++) {
1831                 for(int side = 0; side < heads; side++) {
1832                         if(track_offsets[(track << 1) + side] >= image_size) {
1833                                 continue;
1834                         }
1835                         if((track << 1) + side < 164) {
1836                                 d88_hdr.trkptr[(track << 1) + side] = trkptr;
1837                         }
1838                         
1839                         track_header tr;
1840                         memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
1841                         int pos = track_offsets[(track << 1) + side] + 0x100;
1842                         for(int j = 0; j < tr.number_of_sector; j++) {
1843                                 sector_header sector;
1844                                 memcpy(&sector, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
1845                                 
1846                                 // create d88 sector header
1847                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1848                                 d88_sct.c = sector.track;
1849                                 d88_sct.h = sector.side;
1850                                 d88_sct.r = sector.sector_id;
1851                                 d88_sct.n = sector.sector_size_code;
1852                                 d88_sct.nsec = tr.number_of_sector;
1853                                 if(extendformat) {
1854                                         d88_sct.size = sector.data_length;
1855                                         d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
1856                                 } else {
1857                                         d88_sct.size = 128 << tr.sector_size_code;
1858                                         d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
1859                                 }
1860                                 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
1861                                 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
1862                                 
1863                                 // copy to d88
1864                                 if((track << 1) + side < 164) {
1865                                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1866                                         COPYBUFFER(tmp_buffer + pos, d88_sct.size);
1867                                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1868                                 }
1869                                 total += d88_sct.size;
1870                                 
1871                                 if(extendformat) {
1872                                         pos += sector.data_length;
1873                                 } else {
1874                                         pos += 128 << tr.sector_size_code;
1875                                 }
1876                         }
1877                 }
1878         }
1879         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1880         d88_hdr.size = trkptr;
1881         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1882         return true;
1883 }
1884
1885 // solid image decoder
1886
1887 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
1888 {
1889         int n = 0, t = 0;
1890         
1891         media_type = type;
1892         solid_ncyl = ncyl;
1893         solid_nside = nside;
1894         solid_nsec = nsec;
1895         solid_size = size;
1896         solid_mfm = mfm;
1897         
1898         // create d88 header
1899         d88_hdr_t d88_hdr;
1900         d88_sct_t d88_sct;
1901         
1902         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1903         my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
1904         d88_hdr.protect = 0; // non-protected
1905         
1906         file_size.d = 0;
1907         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1908         
1909         // sector length
1910         for(int i = 0; i < 8; i++) {
1911                 if(size == (128 << i)) {
1912                         n = i;
1913                         break;
1914                 }
1915         }
1916         
1917         // create tracks
1918         int trkptr = sizeof(d88_hdr_t);
1919         
1920         for(int c = 0; c < ncyl; c++) {
1921                 for(int h = 0; h < nside; h++) {
1922                         d88_hdr.trkptr[t++] = trkptr;
1923                         if(nside == 1) {
1924                                 t++;
1925                         }
1926                         
1927                         // read sectors in this track
1928                         for(int s = 0; s < nsec; s++) {
1929                                 // create d88 sector header
1930                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1931                                 d88_sct.c = c;
1932                                 d88_sct.h = h;
1933                                 d88_sct.r = s + 1;
1934                                 d88_sct.n = n;
1935                                 d88_sct.nsec = nsec;
1936                                 d88_sct.dens = 0;
1937                                 d88_sct.del = 0;
1938                                 d88_sct.stat = 0;
1939                                 d88_sct.size = size;
1940                                 
1941                                 // create sector image
1942                                 uint8 dst[16384];
1943                                 memset(dst, 0xe5, sizeof(dst));
1944                                 fio->Fread(dst, size, 1);
1945                                 
1946                                 // copy to d88
1947                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1948                                 COPYBUFFER(dst, size);
1949                                 trkptr += sizeof(d88_sct_t) + size;
1950                         }
1951                 }
1952         }
1953         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
1954         d88_hdr.size = trkptr;
1955         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1956         return true;
1957 }
1958
1959 #define STATE_VERSION   11
1960
1961 void DISK::save_state(FILEIO* state_fio)
1962 {
1963         state_fio->FputUint32(STATE_VERSION);
1964         
1965         state_fio->Fwrite(buffer, sizeof(buffer), 1);
1966         state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
1967         state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
1968         state_fio->FputUint32(file_size.d);
1969         state_fio->FputInt32(file_bank);
1970         state_fio->FputUint32(crc32);
1971         state_fio->FputBool(trim_required);
1972         state_fio->FputBool(is_1dd_image);
1973         state_fio->FputBool(is_solid_image);
1974         state_fio->FputBool(is_fdi_image);
1975         state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
1976         state_fio->FputInt32(solid_ncyl);
1977         state_fio->FputInt32(solid_nside);
1978         state_fio->FputInt32(solid_nsec);
1979         state_fio->FputInt32(solid_size);
1980         state_fio->FputBool(solid_mfm);
1981         state_fio->FputBool(inserted);
1982         state_fio->FputBool(ejected);
1983         state_fio->FputBool(write_protected);
1984         state_fio->FputBool(changed);
1985         state_fio->FputUint8(media_type);
1986         state_fio->FputInt32(is_special_disk);
1987         state_fio->Fwrite(track, sizeof(track), 1);
1988         state_fio->FputInt32(sector_num.sd);
1989         state_fio->FputBool(track_mfm);
1990         state_fio->FputBool(invalid_format);
1991 //      state_fio->FputBool(no_skew);
1992         state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
1993         state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
1994         state_fio->Fwrite(id_position, sizeof(id_position), 1);
1995         state_fio->Fwrite(data_position, sizeof(data_position), 1);
1996         state_fio->FputInt32(gap3_size);
1997         state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
1998         state_fio->FputInt32(sector_size.sd);
1999         state_fio->Fwrite(id, sizeof(id), 1);
2000         state_fio->FputUint8(density);
2001         state_fio->FputBool(deleted);
2002         state_fio->FputBool(addr_crc_error);
2003         state_fio->FputBool(data_crc_error);
2004         state_fio->FputUint8(drive_type);
2005         state_fio->FputInt32(drive_rpm);
2006         state_fio->FputBool(drive_mfm);
2007 }
2008
2009 bool DISK::load_state(FILEIO* state_fio)
2010 {
2011         if(state_fio->FgetUint32() != STATE_VERSION) {
2012                 return false;
2013         }
2014         state_fio->Fread(buffer, sizeof(buffer), 1);
2015         state_fio->Fread(orig_path, sizeof(orig_path), 1);
2016         state_fio->Fread(dest_path, sizeof(dest_path), 1);
2017         file_size.d = state_fio->FgetUint32();
2018         file_bank = state_fio->FgetInt32();
2019         crc32 = state_fio->FgetUint32();
2020         trim_required = state_fio->FgetBool();
2021         is_1dd_image = state_fio->FgetBool();
2022         is_solid_image = state_fio->FgetBool();
2023         is_fdi_image = state_fio->FgetBool();
2024         state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2025         solid_ncyl = state_fio->FgetInt32();
2026         solid_nside = state_fio->FgetInt32();
2027         solid_nsec = state_fio->FgetInt32();
2028         solid_size = state_fio->FgetInt32();
2029         solid_mfm = state_fio->FgetBool();
2030         inserted = state_fio->FgetBool();
2031         ejected = state_fio->FgetBool();
2032         write_protected = state_fio->FgetBool();
2033         changed = state_fio->FgetBool();
2034         media_type = state_fio->FgetUint8();
2035         is_special_disk = state_fio->FgetInt32();
2036         state_fio->Fread(track, sizeof(track), 1);
2037         sector_num.sd = state_fio->FgetInt32();
2038         track_mfm = state_fio->FgetBool();
2039         invalid_format = state_fio->FgetBool();
2040 //      no_skew = state_fio->FgetBool();
2041         state_fio->Fread(sync_position, sizeof(sync_position), 1);
2042         state_fio->Fread(am1_position, sizeof(am1_position), 1);
2043         state_fio->Fread(id_position, sizeof(id_position), 1);
2044         state_fio->Fread(data_position, sizeof(data_position), 1);
2045         gap3_size = state_fio->FgetInt32();
2046         int offset = state_fio->FgetInt32();
2047         sector = (offset != -1) ? buffer + offset : NULL;
2048         sector_size.sd = state_fio->FgetInt32();
2049         state_fio->Fread(id, sizeof(id), 1);
2050         density = state_fio->FgetUint8();
2051         deleted = state_fio->FgetBool();
2052         addr_crc_error = state_fio->FgetBool();
2053         data_crc_error = state_fio->FgetBool();
2054         drive_type = state_fio->FgetUint8();
2055         drive_rpm = state_fio->FgetInt32();
2056         drive_mfm = state_fio->FgetBool();
2057         return true;
2058 }
2059