OSDN Git Service

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