OSDN Git Service

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