OSDN Git Service

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