OSDN Git Service

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