OSDN Git Service

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