OSDN Git Service

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