OSDN Git Service

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