OSDN Git Service

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