OSDN Git Service

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