OSDN Git Service

[VM][General] Merge upstream 2015-08-21.
[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                         }
336                 }
337 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
338                 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
339                 if(media_type == MEDIA_TYPE_2D) {
340                         // check first track
341                         pair offset;
342                         offset.read_4bytes_le_from(buffer + 0x20);
343                         if(IS_VALID_TRACK(offset.d)) {
344                                 // check first sector
345                                 static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
346                                 uint8 *t = buffer + offset.d;
347 #if defined(_X1TURBO) || defined(_X1TURBOZ)
348 //                              if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
349 //                                      is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
350 //                              } else
351 #endif
352                                 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
353                                         is_special_disk = SPECIAL_DISK_X1_BATTEN;
354                                 }
355                         }
356                 }
357 #endif
358         }
359         delete fi;
360 }
361
362 void DISK::close()
363 {
364         // write disk image
365         if(inserted) {
366                 if(trim_required) {
367                         trim_buffer();
368                         trim_required = false;
369                 }
370                 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
371                 
372                 if(/*!write_protected &&*/ file_size.d && getcrc32(buffer, file_size.d) != crc32) {
373                         // write image
374                         FILEIO* fio = new FILEIO();
375                         int pre_size = 0, post_size = 0;
376                         uint8 *pre_buffer = NULL, *post_buffer = NULL;
377                         
378                         // is this d88 format ?
379                         if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
380                                 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
381                                         fio->Fseek(0, FILEIO_SEEK_END);
382                                         uint32 total_size = fio->Ftell(), offset = 0;
383                                         for(int i = 0; i < file_bank; i++) {
384                                                 fio->Fseek(offset + 0x1c, SEEK_SET);
385                                                 offset += fio->FgetUint32_LE();
386                                         }
387                                         if((pre_size = offset) > 0) {
388                                                 pre_buffer = (uint8 *)malloc(pre_size);
389                                                 fio->Fseek(0, FILEIO_SEEK_SET);
390                                                 fio->Fread(pre_buffer, pre_size, 1);
391                                         }
392                                         fio->Fseek(offset + 0x1c, SEEK_SET);
393                                         offset += fio->FgetUint32_LE();
394                                         if((post_size = total_size - offset) > 0) {
395                                                 post_buffer = (uint8 *)malloc(post_size);
396                                                 fio->Fseek(offset, FILEIO_SEEK_SET);
397                                                 fio->Fread(post_buffer, post_size, 1);
398                                         }
399                                         fio->Fclose();
400                                 }
401                         }
402                         if((FILEIO::IsFileExists(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
403                                 _TCHAR tmp_path[_MAX_PATH];
404                                 _stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
405                                 fio->Fopen(emu->bios_path(tmp_path), FILEIO_WRITE_BINARY);
406                         }
407                         if(fio->IsOpened()) {
408                                 if(pre_buffer) {
409                                         fio->Fwrite(pre_buffer, pre_size, 1);
410                                 }
411                                 if(is_solid_image) {
412                                         if(is_fdi_image) {
413                                                 fio->Fwrite(fdi_header, 4096, 1);
414                                         }
415                                         for(int trkside = 0; trkside < 164; trkside++) {
416                                                 pair offset;
417                                                 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
418                                                 
419                                                 if(!IS_VALID_TRACK(offset.d)) {
420                                                         break;
421                                                 }
422                                                 uint8* t = buffer + offset.d;
423                                                 pair sector_num, data_size;
424                                                 sector_num.read_2bytes_le_from(t + 4);
425                                                 
426                                                 for(int i = 0; i < sector_num.sd; i++) {
427                                                         data_size.read_2bytes_le_from(t + 14);
428                                                         fio->Fwrite(t + 0x10, data_size.sd, 1);
429                                                         t += data_size.sd + 0x10;
430                                                 }
431                                         }
432                                 } else {
433                                         fio->Fwrite(buffer, file_size.d, 1);
434                                 }
435                                 if(post_buffer) {
436                                         fio->Fwrite(post_buffer, post_size, 1);
437                                 }
438                                 fio->Fclose();
439                         }
440                         if(pre_buffer) {
441                                 free(pre_buffer);
442                         }
443                         if(post_buffer) {
444                                 free(post_buffer);
445                         }
446                         delete fio;
447                 }
448                 ejected = true;
449         }
450         inserted = write_protected = false;
451         file_size.d = 0;
452         sector_size.sd = sector_num.sd = 0;
453         sector = NULL;
454 }
455
456 bool DISK::get_track(int trk, int side)
457 {
458         sector_size.sd = sector_num.sd = 0;
459         invalid_format = false;
460         no_skew = true;
461         
462         // disk not inserted or invalid media type
463         if(!(inserted && check_media_type())) {
464                 return false;
465         }
466         
467         // search track
468         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
469         if(!(0 <= trkside && trkside < 164)) {
470                 return false;
471         }
472         cur_track = trk;
473         cur_side = side;
474         if(media_type == MEDIA_TYPE_2D) {
475                 if((drive_type == DRIVE_TYPE_2DD) ||
476                    (drive_type == DRIVE_TYPE_2HD) ||
477                    (drive_type == DRIVE_TYPE_144)) {
478                         if(trk & 1 != 0) {
479                                 for(int i = 0; i < get_track_size(); i++) {
480                                         track[i] = rand();
481                                 }
482                                 return false;
483                         }
484                         cur_track = cur_track >> 1;
485                 }
486         }
487         
488         pair offset;
489         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
490         
491         if(!IS_VALID_TRACK(offset.d)) {
492                 return false;
493         }
494         
495         // track found
496         sector = buffer + offset.d;
497         sector_num.read_2bytes_le_from(sector + 4);
498         pair data_size;
499         data_size.read_2bytes_le_from(sector + 14);
500         
501         // create each sector position in track
502         int sync_size  = drive_mfm ? 12 : 6;
503         int am_size = drive_mfm ? 3 : 0;
504         int gap0_size = drive_mfm ? 80 : 40;
505         int gap1_size = drive_mfm ? 50 : 26;
506         int gap2_size = drive_mfm ? 22 : 11;
507         int gap3_size = 0, gap4_size;
508         
509         if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
510                 if(drive_mfm) {
511                         if(data_size.sd ==  256 && sector_num.sd == 26) gap3_size =  54;
512                         if(data_size.sd ==  512 && sector_num.sd == 15) gap3_size =  84;
513                         if(data_size.sd == 1024 && sector_num.sd ==  8) gap3_size = 116;
514                 } else {
515                         if(data_size.sd ==  128 && sector_num.sd == 26) gap3_size =  27;
516                         if(data_size.sd ==  256 && sector_num.sd == 15) gap3_size =  42;
517                         if(data_size.sd ==  512 && sector_num.sd ==  8) gap3_size =  58;
518                 }
519         } else {
520                 if(drive_mfm) {
521                         if(data_size.sd ==  256 && sector_num.sd == 16) gap3_size =  51;
522                         if(data_size.sd ==  512 && sector_num.sd ==  9) gap3_size =  80;
523                         if(data_size.sd == 1024 && sector_num.sd ==  5) gap3_size = 116;
524                 } else {
525                         if(data_size.sd ==  128 && sector_num.sd == 16) gap3_size =  27;
526                         if(data_size.sd ==  256 && sector_num.sd ==  9) gap3_size =  42;
527                         if(data_size.sd ==  512 && sector_num.sd ==  5) gap3_size =  58;
528                 }
529         }
530         
531         uint8* t = sector;
532         int total = sync_size + (am_size + 1);
533         
534         for(int i = 0; i < sector_num.sd; i++) {
535                 data_size.read_2bytes_le_from(t + 14);
536                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
537                 if(data_size.sd > 0) {
538                         total += sync_size + (am_size + 1);
539                         total += data_size.sd + 2;
540                 }
541                 if(t[2] != i + 1) {
542                         no_skew = false;
543                 }
544                 t += data_size.sd + 0x10;
545         }
546         if(gap3_size == 0) {
547                 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (sector_num.sd + 1);
548         }
549         gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
550         
551         if(gap3_size < 8 || gap4_size < 8) {
552                 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + sector_num.sd + 1);
553                 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
554         }
555         if(gap3_size < 8 || gap4_size < 8) {
556                 gap0_size = gap1_size = gap3_size = gap4_size = 32;
557                 invalid_format = true;
558         }
559         int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
560         
561         t = sector;
562         total = preamble_size;
563         sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
564         
565         for(int i = 0; i < sector_num.sd; i++) {
566                 data_size.read_2bytes_le_from(t + 14);
567                 if(invalid_format) {
568                         total = preamble_size + (get_track_size() - preamble_size - gap4_size) * i / sector_num.sd;
569                 }
570                 sync_position[i] = total;
571                 total += sync_size + (am_size + 1);
572                 id_position[i] = total;
573                 total += (4 + 2) + gap2_size;
574                 if(data_size.sd > 0) {
575                         total += sync_size + (am_size + 1);
576                         data_position[i] = total;
577                         total += data_size.sd + 2;
578                 } else {
579                         data_position[i] = total; // FIXME
580                 }
581                 total += gap3_size;
582                 t += data_size.sd + 0x10;
583         }
584         return true;
585 }
586
587 bool DISK::make_track(int trk, int side)
588 {
589         int track_size = get_track_size();
590         
591         if(!get_track(trk, side)) {
592                 // create a dummy track
593                 for(int i = 0; i < track_size; i++) {
594                         track[i] = rand();
595                 }
596                 return false;
597         }
598         
599         // make track image
600         int sync_size  = drive_mfm ? 12 : 6;
601         int am_size = drive_mfm ? 3 : 0;
602         int gap2_size = drive_mfm ? 22 : 11;
603         uint8 gap_data = drive_mfm ? 0x4e : 0xff;
604         
605         // preamble
606         memset(track, gap_data, track_size);
607         int q = sync_position[array_length(sync_position) - 1];
608         
609         // sync
610         for(int i = 0; i < sync_size; i++) {
611                 track[q++] = 0x00;
612         }
613         // index mark
614         for(int i = 0; i < am_size; i++) {
615                 track[q++] = 0xc2;
616         }
617         track[q++] = 0xfc;
618         
619         // sectors
620         uint8 *t = sector;
621         
622         for(int i = 0; i < sector_num.sd; i++) {
623                 pair data_size;
624                 data_size.read_2bytes_le_from(t + 14);
625                 int p = sync_position[i];
626                 
627                 // sync
628                 for(int j = 0; j < sync_size; j++) {
629                         if(p < track_size) track[p++] = 0x00;
630                 }
631                 // am1
632                 for(int j = 0; j < am_size; j++) {
633                         if(p < track_size) track[p++] = 0xa1;
634                 }
635                 if(p < track_size) track[p++] = 0xfe;
636                 // id
637                 if(p < track_size) track[p++] = t[0];
638                 if(p < track_size) track[p++] = t[1];
639                 if(p < track_size) track[p++] = t[2];
640                 if(p < track_size) track[p++] = t[3];
641                 uint16 crc = 0;
642                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
643                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
644                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
645                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
646                 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
647                 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
648                 // gap2
649                 for(int j = 0; j < gap2_size; j++) {
650                         if(p < track_size) track[p++] = gap_data;
651                 }
652                 // data field
653                 if(data_size.sd > 0) {
654                         // sync
655                         for(int j = 0; j < sync_size; j++) {
656                                 if(p < track_size) track[p++] = 0x00;
657                         }
658                         // am2
659                         for(int j = 0; j < am_size; j++) {
660                                 if(p < track_size) track[p++] = 0xa1;
661                         }
662                         if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
663                         // data
664                         crc = 0;
665                         for(int j = 0; j < data_size.sd; j++) {
666                                 if(p < track_size) track[p++] = t[0x10 + j];
667                                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
668                         }
669                         if(p < track_size) track[p++] = (crc >> 8) & 0xff;
670                         if(p < track_size) track[p++] = (crc >> 0) & 0xff;
671                 }
672                 t += data_size.sd + 0x10;
673         }
674         return true;
675 }
676
677 bool DISK::get_sector(int trk, int side, int index)
678 {
679         sector_size.sd = sector_num.sd = 0;
680         sector = NULL;
681         
682         // disk not inserted or invalid media type
683         if(!(inserted && check_media_type())) {
684                 return false;
685         }
686         
687         // search track
688         if(trk == -1 && side == -1) {
689                 trk = cur_track;
690                 side = cur_side;
691         }
692         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
693         if(!(0 <= trkside && trkside < 164)) {
694                 return false;
695         }
696         pair offset;
697         offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
698         
699         if(!IS_VALID_TRACK(offset.d)) {
700                 return false;
701         }
702         
703         // track found
704         uint8* t = buffer + offset.d;
705         sector_num.read_2bytes_le_from(t + 4);
706         
707         if(index >= sector_num.sd) {
708                 return false;
709         }
710         
711         // skip sector
712         for(int i = 0; i < index; i++) {
713                 pair data_size;
714                 data_size.read_2bytes_le_from(t + 14);
715                 t += data_size.sd + 0x10;
716         }
717         set_sector_info(t);
718         return true;
719 }
720
721 void DISK::set_sector_info(uint8 *t)
722 {
723         // header info
724         id[0] = t[0];
725         id[1] = t[1];
726         id[2] = t[2];
727         id[3] = t[3];
728         uint16 crc = 0;
729         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
730         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
731         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
732         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
733         id[4] = (crc >> 8) & 0xff;
734         id[5] = (crc >> 0) & 0xff;
735         // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
736         // t[6]: 0x00 = double-density, 0x40 = single-density
737         // t[7]: 0x00 = normal, 0x10 = deleted mark
738         // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
739         density = t[6];
740         deleted = (t[7] != 0);
741    
742 //      if(ignore_crc()) {
743 //              crc_error = false;
744 //      } else {
745 //              crc_error = (((t[8] & 0xf0) != 0x00) && ((t[8] & 0xf0) != 0x10));
746                 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
747                 data_crc_error = ((t[8] & 0xf0) == 0xb0);
748 //      }
749         sector = t + 0x10;
750         sector_size.read_2bytes_le_from(t + 14);
751 }
752
753 void DISK::set_deleted(bool value)
754 {
755         if(sector != NULL) {
756                 uint8 *t = sector - 0x10;
757                 t[7] = value ? 0x10 : 0;
758                 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
759                         t[8] = (t[8] & 0x0f) | t[7];
760                 }
761         }
762         deleted = value;
763 }
764
765 void DISK::set_data_crc_error(bool value)
766 {
767         if(sector != NULL) {
768                 uint8 *t = sector - 0x10;
769                 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
770         }
771         data_crc_error = value;
772 }
773
774 void DISK::set_data_mark_missing()
775 {
776         if(sector != NULL) {
777                 uint8 *t = sector - 0x10;
778                 //t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]); // FIXME: always data crc error ?
779                 t[8] = (t[8] & 0x0f) | 0xf0;
780                 t[14] = t[15] = 0;
781
782         }
783         //addr_crc_error = value;
784         data_crc_error = false;
785 }
786
787 bool DISK::format_track(int trk, int side)
788 {
789         // disk not inserted or invalid media type
790         if(!(inserted && check_media_type())) {
791                 return false;
792         }
793         
794         // search track
795         int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
796         if(!(0 <= trkside && trkside < 164)) {
797                 return false;
798         }
799         
800         // create new empty track
801         if(trim_required) {
802                 trim_buffer();
803                 trim_required = false;
804         }
805         memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
806         pair offset;
807         offset.d = DISK_BUFFER_SIZE;
808         offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
809         
810         trim_required = true;
811         sector_num.sd = 0;
812         return true;
813 }
814
815 void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool data_crc_error, uint8 fill_data, int length)
816 {
817         uint8* t = buffer + DISK_BUFFER_SIZE;
818         
819         sector_num.sd++;
820         for(int i = 0; i < (sector_num.sd - 1); i++) {
821                 t[4] = sector_num.b.l;
822                 t[5] = sector_num.b.h;
823                 pair data_size;
824                 data_size.read_2bytes_le_from(t + 14);
825                 t += data_size.sd + 0x10;
826         }
827         t[0] = c;
828         t[1] = h;
829         t[2] = r;
830         t[3] = n;
831         t[4] = sector_num.b.l;
832         t[5] = sector_num.b.h;
833         t[6] = drive_mfm ? 0 : 0x40;
834         t[7] = deleted ? 0x10 : 0;
835         t[8] = data_crc_error ? 0xb0 : t[7];
836         t[14] = (length >> 0) & 0xff;
837         t[15] = (length >> 8) & 0xff;
838         memset(t + 16, fill_data, length);
839         
840         set_sector_info(t);
841 }
842
843 void DISK::sync_buffer()
844 {
845         if(trim_required) {
846                 trim_buffer();
847                 trim_required = false;
848         }
849 }
850
851 void DISK::trim_buffer()
852 {
853         int max_tracks = 164;
854         uint32 dest_offset = 0x2b0;
855         
856         // copy header
857         memset(tmp_buffer, 0, sizeof(tmp_buffer));
858         memcpy(tmp_buffer, buffer, 0x20);
859         
860         // check max tracks
861         for(int trkside = 0; trkside < 164; trkside++) {
862                 pair src_trk_offset;
863                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
864                 if(src_trk_offset.d != 0) {
865 #if 1
866                         if(src_trk_offset.d < 0x2b0) {
867                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
868                         }
869 #else
870                         if(src_trk_offset.d != 0x2b0) {
871                                 max_tracks = (src_trk_offset.d - 0x20) >> 2;
872                                 if(max_tracks > 164) {
873                                         dest_offset = 0x20 + max_tracks * 4);
874                                 }
875                         }
876 #endif
877                         break;
878                 }
879         }
880         
881         // copy tracks
882         for(int trkside = 0; trkside < max_tracks; trkside++) {
883                 pair src_trk_offset;
884                 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
885                 
886                 pair dest_trk_offset;
887                 dest_trk_offset.d = 0;
888                 
889                 if(IS_VALID_TRACK(src_trk_offset.d)) {
890                         uint8* t = buffer + src_trk_offset.d;
891                         pair sector_num, data_size;
892                         sector_num.read_2bytes_le_from(t + 4);
893                         if(sector_num.sd != 0) {
894                                 dest_trk_offset.d = dest_offset;
895                                 for(int i = 0; i < sector_num.sd; i++) {
896                                         data_size.read_2bytes_le_from(t + 14);
897                                         memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
898                                         dest_offset += data_size.sd + 0x10;
899                                         t += data_size.sd + 0x10;
900                                 }
901                         }
902                 }
903                 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
904         }
905         
906         // update file size
907         file_size.d = dest_offset;
908         file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
909         
910         memset(buffer, 0, sizeof(buffer));
911         memcpy(buffer, tmp_buffer, (file_size.d > sizeof(buffer)) ? sizeof(buffer) : file_size.d);
912 }
913
914 int DISK::get_rpm()
915 {
916         if(drive_rpm != 0) {
917                 return drive_rpm;
918         } else if(inserted) {
919                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
920         } else {
921                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
922         }
923 }
924
925 int DISK::get_track_size()
926 {
927         if(inserted) {
928                 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
929                         return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3100;
930                 }
931                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
932         } else {
933                 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
934                         return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3100;
935                 }
936                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
937         }
938 }
939
940 double DISK::get_usec_per_track()
941 {
942         return 1000000.0 / (get_rpm() / 60.0);
943 }
944
945 double DISK::get_usec_per_bytes(int bytes)
946 {
947         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
948 }
949
950 int DISK::get_bytes_per_usec(double usec)
951 {
952         return (int)(usec / get_usec_per_bytes(1) + 0.5);
953 }
954
955 bool DISK::check_media_type()
956 {
957         switch(drive_type) {
958         case DRIVE_TYPE_2D:
959                 return (media_type == MEDIA_TYPE_2D);
960         case DRIVE_TYPE_2DD:
961                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
962         case DRIVE_TYPE_2HD:
963                 return (media_type == MEDIA_TYPE_2HD);
964         case DRIVE_TYPE_144:
965                 return (media_type == MEDIA_TYPE_144);
966         case DRIVE_TYPE_UNK:
967                 return true; // always okay
968         }
969         return false;
970 }
971
972 // image decoder
973
974 #define COPYBUFFER(src, size) { \
975         if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
976                 return false; \
977         } \
978         memcpy(buffer + file_size.d, (src), (size)); \
979         file_size.d += (size); \
980 }
981
982 typedef struct {
983         char title[17];
984         uint8 rsrv[9];
985         uint8 protect;
986         uint8 type;
987         uint32 size;
988         uint32 trkptr[164];
989 } d88_hdr_t;
990
991 typedef struct {
992         uint8 c, h, r, n;
993         uint16 nsec;
994         uint8 dens, del, stat;
995         uint8 rsrv[5];
996         uint16 size;
997 } d88_sct_t;
998
999 // teledisk image decoder
1000
1001 /*
1002         this teledisk image decoder is based on:
1003         
1004                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1005                 LZSS coded by Haruhiko OKUMURA
1006                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1007                 Edited and translated to English by Kenji RIKITAKE
1008                 TDLZHUF.C by WTK
1009 */
1010
1011 typedef struct {
1012         char sig[3];
1013         uint8 unknown;
1014         uint8 ver;
1015         uint8 dens;
1016         uint8 type;
1017         uint8 flag;
1018         uint8 dos;
1019         uint8 sides;
1020         uint16 crc;
1021 } td_hdr_t;
1022
1023 typedef struct {
1024         uint16 crc;
1025         uint16 len;
1026         uint8 ymd[3];
1027         uint8 hms[3];
1028 } td_cmt_t;
1029
1030 typedef struct {
1031         uint8 nsec, trk, head;
1032         uint8 crc;
1033 } td_trk_t;
1034
1035 typedef struct {
1036         uint8 c, h, r, n;
1037         uint8 ctrl, crc;
1038 } td_sct_t;
1039
1040 bool DISK::teledisk_to_d88()
1041 {
1042         td_hdr_t hdr;
1043         td_cmt_t cmt;
1044         td_trk_t trk;
1045         td_sct_t sct;
1046         d88_hdr_t d88_hdr;
1047         d88_sct_t d88_sct;
1048         uint8 obuf[512];
1049         
1050         // check teledisk header
1051         fi->Fseek(0, FILEIO_SEEK_SET);
1052         fi->Fread(&hdr, sizeof(td_hdr_t), 1);
1053         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1054                 // decompress to the temporary file
1055                 FILEIO* fo = new FILEIO();
1056                 if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {
1057                         delete fo;
1058                         return false;
1059                 }
1060                 int rd = 1;
1061                 init_decode();
1062                 do {
1063                         if((rd = decode(obuf, 512)) > 0) {
1064                                 fo->Fwrite(obuf, rd, 1);
1065                         }
1066                 }
1067                 while(rd > 0);
1068                 fo->Fclose();
1069                 delete fo;
1070                 temporary = true;
1071                 
1072                 // reopen the temporary file
1073                 fi->Fclose();
1074                 if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {
1075                         return false;
1076                 }
1077         }
1078         if(hdr.flag & 0x80) {
1079                 // skip comment
1080                 fi->Fread(&cmt, sizeof(td_cmt_t), 1);
1081                 fi->Fseek(cmt.len, FILEIO_SEEK_CUR);
1082         }
1083         
1084         // create d88 image
1085         file_size.d = 0;
1086         
1087         // create d88 header
1088         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1089         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1090         d88_hdr.protect = 0; // non-protected
1091         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1092         
1093         // create tracks
1094         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1095         fi->Fread(&trk, sizeof(td_trk_t), 1);
1096         while(trk.nsec != 0xff) {
1097                 d88_hdr.trkptr[trkcnt++] = trkptr;
1098                 if(hdr.sides == 1) {
1099                         trkcnt++;
1100                 }
1101                 
1102                 // read sectors in this track
1103                 for(int i = 0; i < trk.nsec; i++) {
1104                         uint8 buf[2048], dst[2048];
1105                         memset(buf, 0, sizeof(buf));
1106                         memset(dst, 0, sizeof(dst));
1107                         
1108                         // read sector header
1109                         fi->Fread(&sct, sizeof(td_sct_t), 1);
1110                         
1111                         // create d88 sector header
1112                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1113                         d88_sct.c = sct.c;
1114                         d88_sct.h = sct.h;
1115                         d88_sct.r = sct.r;
1116                         d88_sct.n = sct.n;
1117                         d88_sct.nsec = trk.nsec;
1118                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1119                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1120                         d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1121                         d88_sct.size = secsize[sct.n & 3];
1122                         
1123                         // create sector image
1124                         if(sct.ctrl & 0x30) {
1125                                 d88_sct.stat = 0xf0; // data mark missing
1126                                 d88_sct.size = 0;
1127                         } else {
1128                                 // read sector source
1129                                 int len = fi->Fgetc();
1130                                 len += fi->Fgetc() * 256 - 1;
1131                                 int flag = fi->Fgetc(), d = 0;
1132                                 fi->Fread(buf, len, 1);
1133                                 
1134                                 // convert
1135                                 if(flag == 0) {
1136                                         memcpy(dst, buf, len);
1137                                 } else if(flag == 1) {
1138                                         pair len2;
1139                                         len2.read_2bytes_le_from(buf);
1140                                         while(len2.sd--) {
1141                                                 dst[d++] = buf[2];
1142                                                 dst[d++] = buf[3];
1143                                         }
1144                                 } else if(flag == 2) {
1145                                         for(int s = 0; s < len;) {
1146                                                 int type = buf[s++];
1147                                                 int len2 = buf[s++];
1148                                                 if(type == 0) {
1149                                                         while(len2--) {
1150                                                                 dst[d++] = buf[s++];
1151                                                         }
1152                                                 } else if(type < 5) {
1153                                                         uint8 pat[256];
1154                                                         int n = 2;
1155                                                         while(type-- > 1) {
1156                                                                 n *= 2;
1157                                                         }
1158                                                         for(int j = 0; j < n; j++) {
1159                                                                 pat[j] = buf[s++];
1160                                                         }
1161                                                         while(len2--) {
1162                                                                 for(int j = 0; j < n; j++) {
1163                                                                         dst[d++] = pat[j];
1164                                                                 }
1165                                                         }
1166                                                 } else {
1167                                                         break; // unknown type
1168                                                 }
1169                                         }
1170                                 } else {
1171                                         break; // unknown flag
1172                                 }
1173                         }
1174                         
1175                         // copy to d88
1176                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1177                         COPYBUFFER(dst, d88_sct.size);
1178                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1179                 }
1180                 // read next track
1181                 fi->Fread(&trk, sizeof(td_trk_t), 1);
1182         }
1183         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 45) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1184         d88_hdr.size = trkptr;
1185         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1186         return true;
1187 }
1188
1189 int DISK::next_word()
1190 {
1191         if(ibufndx >= ibufcnt) {
1192                 ibufndx = ibufcnt = 0;
1193                 memset(inbuf, 0, 512);
1194                 for(int i = 0; i < 512; i++) {
1195                         int d = fi->Fgetc();
1196                         if(d == EOF) {
1197                                 if(i) {
1198                                         break;
1199                                 }
1200                                 return(-1);
1201                         }
1202                         inbuf[i] = d;
1203                         ibufcnt = i + 1;
1204                 }
1205         }
1206         while(getlen <= 8) {
1207                 getbuf |= inbuf[ibufndx++] << (8 - getlen);
1208                 getlen += 8;
1209         }
1210         return 0;
1211 }
1212
1213 int DISK::get_bit()
1214 {
1215         if(next_word() < 0) {
1216                 return -1;
1217         }
1218         short i = getbuf;
1219         getbuf <<= 1;
1220         getlen--;
1221         return (i < 0) ? 1 : 0;
1222 }
1223
1224 int DISK::get_byte()
1225 {
1226         if(next_word() != 0) {
1227                 return -1;
1228         }
1229         uint16 i = getbuf;
1230         getbuf <<= 8;
1231         getlen -= 8;
1232         i >>= 8;
1233         return (int)i;
1234 }
1235
1236 void DISK::start_huff()
1237 {
1238         int i, j;
1239         for(i = 0; i < N_CHAR; i++) {
1240                 freq[i] = 1;
1241                 son[i] = i + TABLE_SIZE;
1242                 prnt[i + TABLE_SIZE] = i;
1243         }
1244         i = 0; j = N_CHAR;
1245         while(j <= ROOT_POSITION) {
1246                 freq[j] = freq[i] + freq[i + 1];
1247                 son[j] = i;
1248                 prnt[i] = prnt[i + 1] = j;
1249                 i += 2; j++;
1250         }
1251         freq[TABLE_SIZE] = 0xffff;
1252         prnt[ROOT_POSITION] = 0;
1253 }
1254
1255 void DISK::reconst()
1256 {
1257         short i, j = 0, k;
1258         uint16 f, l;
1259         for(i = 0; i < TABLE_SIZE; i++) {
1260                 if(son[i] >= TABLE_SIZE) {
1261                         freq[j] = (freq[i] + 1) / 2;
1262                         son[j] = son[i];
1263                         j++;
1264                 }
1265         }
1266         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1267                 k = i + 1;
1268                 f = freq[j] = freq[i] + freq[k];
1269                 for(k = j - 1; f < freq[k]; k--);
1270                 k++;
1271                 l = (j - k) * 2;
1272                 memmove(&freq[k + 1], &freq[k], l);
1273                 freq[k] = f;
1274                 memmove(&son[k + 1], &son[k], l);
1275                 son[k] = i;
1276         }
1277         for(i = 0; i < TABLE_SIZE; i++) {
1278                 if((k = son[i]) >= TABLE_SIZE) {
1279                         prnt[k] = i;
1280                 } else {
1281                         prnt[k] = prnt[k + 1] = i;
1282                 }
1283         }
1284 }
1285
1286 void DISK::update(int c)
1287 {
1288         int i, j, k, l;
1289         if(freq[ROOT_POSITION] == MAX_FREQ) {
1290                 reconst();
1291         }
1292         c = prnt[c + TABLE_SIZE];
1293         do {
1294                 k = ++freq[c];
1295                 if(k > freq[l = c + 1]) {
1296                         while(k > freq[++l]);
1297                         l--;
1298                         freq[c] = freq[l];
1299                         freq[l] = k;
1300                         i = son[c];
1301                         prnt[i] = l;
1302                         if(i < TABLE_SIZE) {
1303                                 prnt[i + 1] = l;
1304                         }
1305                         j = son[l];
1306                         son[l] = i;
1307                         prnt[j] = c;
1308                         if(j < TABLE_SIZE) {
1309                                 prnt[j + 1] = c;
1310                         }
1311                         son[c] = j;
1312                         c = l;
1313                 }
1314         }
1315         while((c = prnt[c]) != 0);
1316 }
1317
1318 short DISK::decode_char()
1319 {
1320         int ret;
1321         uint16 c = son[ROOT_POSITION];
1322         while(c < TABLE_SIZE) {
1323                 if((ret = get_bit()) < 0) {
1324                         return -1;
1325                 }
1326                 c += (unsigned)ret;
1327                 c = son[c];
1328         }
1329         c -= TABLE_SIZE;
1330         update(c);
1331         return c;
1332 }
1333
1334 short DISK::decode_position()
1335 {
1336         short bit;
1337         uint16 i, j, c;
1338         if((bit = get_byte()) < 0) {
1339                 return -1;
1340         }
1341         i = (uint16)bit;
1342         c = (uint16)d_code[i] << 6;
1343         j = d_len[i] - 2;
1344         while(j--) {
1345                 if((bit = get_bit()) < 0) {
1346                          return -1;
1347                 }
1348                 i = (i << 1) + bit;
1349         }
1350         return (c | i & 0x3f);
1351 }
1352
1353 void DISK::init_decode()
1354 {
1355         ibufcnt= ibufndx = bufcnt = getbuf = 0;
1356         getlen = 0;
1357         start_huff();
1358         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1359                 text_buf[i] = ' ';
1360         }
1361         ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1362 }
1363
1364 int DISK::decode(uint8 *buf, int len)
1365 {
1366         short c, pos;
1367         int  count;
1368         for(count = 0; count < len;) {
1369                 if(bufcnt == 0) {
1370                         if((c = decode_char()) < 0) {
1371                                 return count;
1372                         }
1373                         if(c < 256) {
1374                                 *(buf++) = (uint8)c;
1375                                 text_buf[ptr++] = (uint8)c;
1376                                 ptr &= (STRING_BUFFER_SIZE - 1);
1377                                 count++;
1378                         } else {
1379                                 if((pos = decode_position()) < 0) {
1380                                         return count;
1381                                 }
1382                                 bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1383                                 bufcnt = c - 255 + THRESHOLD;
1384                                 bufndx = 0;
1385                         }
1386                 } else {
1387                         while(bufndx < bufcnt && count < len) {
1388                                 c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];
1389                                 *(buf++) = (uint8)c;
1390                                 bufndx++;
1391                                 text_buf[ptr++] = (uint8)c;
1392                                 ptr &= (STRING_BUFFER_SIZE - 1);
1393                                 count++;
1394                         }
1395                         if(bufndx >= bufcnt) {
1396                                 bufndx = bufcnt = 0;
1397                         }
1398                 }
1399         }
1400         return count;
1401 }
1402
1403 // imagedisk image decoder
1404
1405 typedef struct {
1406         uint8 mode;
1407         uint8 cyl;
1408         uint8 head;
1409         uint8 nsec;
1410         uint8 size;
1411 } imd_trk_t;
1412
1413 bool DISK::imagedisk_to_d88()
1414 {
1415         imd_trk_t trk;
1416         d88_hdr_t d88_hdr;
1417         d88_sct_t d88_sct;
1418         
1419         // skip comment
1420         fi->Fseek(0, FILEIO_SEEK_SET);
1421         int tmp;
1422         while((tmp = fi->Fgetc()) != 0x1a) {
1423                 if(tmp == EOF) {
1424                         return false;
1425                 }
1426         }
1427         
1428         // create d88 image
1429         file_size.d = 0;
1430         
1431         // create d88 header
1432         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1433         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1434         d88_hdr.protect = 0; // non-protected
1435         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1436         
1437         // create tracks
1438         int trkptr = sizeof(d88_hdr_t);
1439         int trkcnt = 0, mode;
1440         
1441         for(int t = 0; t < 164; t++) {
1442                 // check end of file
1443                 if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {
1444                         break;
1445                 }
1446                 trkcnt = t;
1447                 
1448                 // check track header
1449                 if(t == 0) {
1450                         mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps
1451                 }
1452                 if(!trk.nsec) {
1453                         continue;
1454                 }
1455                 d88_hdr.trkptr[t] = trkptr;
1456                 
1457                 // setup sector id
1458                 uint8 c[64], h[64], r[64];
1459                 fi->Fread(r, trk.nsec, 1);
1460                 if(trk.head & 0x80) {
1461                         fi->Fread(c, trk.nsec, 1);
1462                 } else {
1463                         memset(c, trk.cyl, sizeof(c));
1464                 }
1465                 if(trk.head & 0x40) {
1466                         fi->Fread(h, trk.nsec, 1);
1467                 } else {
1468                         memset(h, trk.head & 1, sizeof(h));
1469                 }
1470                 
1471                 // read sectors in this track
1472                 for(int i = 0; i < trk.nsec; i++) {
1473                         // create d88 sector header
1474                         int sectype = fi->Fgetc();
1475                         if(sectype > 8) {
1476                                 return false;
1477                         }
1478                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1479                         d88_sct.c = c[i];
1480                         d88_sct.h = h[i];
1481                         d88_sct.r = r[i];
1482                         d88_sct.n = trk.size;
1483                         d88_sct.nsec = trk.nsec;
1484                         d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;
1485                         d88_sct.del = (sectype == 3 || sectype == 4 || sectype == 7 || sectype == 8) ? 0x10 : 0;
1486                         d88_sct.stat = (sectype == 5 || sectype == 6 || sectype == 7 || sectype == 8) ? 0xb0 : d88_sct.del;
1487                         d88_sct.size = secsize[trk.size & 7];
1488                         
1489                         // create sector image
1490                         uint8 dst[8192];
1491                         if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {
1492                                 // uncompressed
1493                                 fi->Fread(dst, d88_sct.size, 1);
1494                         } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {
1495                                 // compressed
1496                                 int tmp = fi->Fgetc();
1497                                 memset(dst, tmp, d88_sct.size);
1498                         } else {
1499                                 d88_sct.stat = 0xf0; // data mark missing
1500                                 d88_sct.size = 0;
1501                         }
1502                         
1503                         // copy to d88
1504                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1505                         COPYBUFFER(dst, d88_sct.size);
1506                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1507                 }
1508         }
1509         d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1510         d88_hdr.size = trkptr;
1511         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1512         return true;
1513 }
1514
1515 // cpdread image decoder (from MESS formats/dsk_dsk.c)
1516
1517 bool DISK::cpdread_to_d88(int extended)
1518 {
1519         d88_hdr_t d88_hdr;
1520         d88_sct_t d88_sct;
1521         int total = 0;
1522         
1523         // get cylinder number and side number
1524         memcpy(tmp_buffer, buffer, file_size.d);
1525         int ncyl = tmp_buffer[0x30];
1526         int nside = tmp_buffer[0x31];
1527         
1528         // create d88 image
1529         file_size.d = 0;
1530         
1531         // create d88 header
1532         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1533         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDRead");
1534         d88_hdr.protect = 0; // non-protected
1535         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1536         
1537         // create tracks
1538         int trkofs = 0x100, trkofs_ptr = 0x34;
1539         int trkptr = sizeof(d88_hdr_t);
1540         
1541         for(int c = 0; c < ncyl; c++) {
1542                 for(int h = 0; h < nside; h++) {
1543                         // read sectors in this track
1544                         uint8 *track_info = tmp_buffer + trkofs;
1545                         int cyl = track_info[0x10];
1546                         int side = track_info[0x11] & 1;
1547                         int nsec = track_info[0x15];
1548                         int size = 1 << (track_info[0x14] + 7); // standard
1549                         int sctofs = trkofs + 0x100;
1550                         
1551                         if(nside == 1) {
1552                                 side = 0;
1553                         }
1554                         d88_hdr.trkptr[2 * cyl + side] = trkptr;
1555                         
1556                         for(int s = 0; s < nsec; s++) {
1557                                 // get sector size
1558                                 uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;
1559                                 if(extended) {
1560                                         size = sector_info[6] + sector_info[7] * 256;
1561                                 }
1562                                 
1563                                 // create d88 sector header
1564                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1565                                 d88_sct.c = sector_info[0];
1566                                 d88_sct.h = sector_info[1];
1567                                 d88_sct.r = sector_info[2];
1568                                 d88_sct.n = sector_info[3];
1569                                 d88_sct.nsec = nsec;
1570                                 d88_sct.dens = 0;
1571                                 d88_sct.del = (sector_info[5] == 0xb2) ? 0x10 : 0;
1572                                 d88_sct.stat = (size == 0) ? 0xf0 : (sector_info[5] == 0xb5) ? 0xb0 : d88_sct.del;
1573                                 d88_sct.size = size;
1574                                 
1575                                 // copy to d88
1576                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1577                                 COPYBUFFER(tmp_buffer + sctofs, size);
1578                                 trkptr += sizeof(d88_sct_t) + size;
1579                                 sctofs += size;
1580                                 total += size;
1581                         }
1582                         
1583                         if(extended) {
1584                                 trkofs += tmp_buffer[trkofs_ptr++] * 256;
1585                         } else {
1586                                 trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1587                         }
1588                 }
1589         }
1590         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1591         d88_hdr.size = trkptr;
1592         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1593         return true;
1594 }
1595
1596 // solid image decoder
1597
1598 bool DISK::solid_to_d88(int type, int ncyl, int nside, int nsec, int size)
1599 {
1600         d88_hdr_t d88_hdr;
1601         d88_sct_t d88_sct;
1602         int n = 0, t = 0;
1603         
1604         file_size.d = 0;
1605         
1606         // create d88 header
1607         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1608         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "STANDARD");
1609         d88_hdr.protect = 0; // non-protected
1610         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
1611         media_type = type;
1612         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1613         
1614         // sector length
1615         for(int i = 0; i < 8; i++) {
1616                 if(size == (128 << i)) {
1617                         n = i;
1618                         break;
1619                 }
1620         }
1621         
1622         // create tracks
1623         int trkptr = sizeof(d88_hdr_t);
1624         for(int c = 0; c < ncyl; c++) {
1625                 for(int h = 0; h < nside; h++) {
1626                         d88_hdr.trkptr[t++] = trkptr;
1627                         if(nside == 1) {
1628                                 t++;
1629                         }
1630                         
1631                         // read sectors in this track
1632                         for(int s = 0; s < nsec; s++) {
1633                                 // create d88 sector header
1634                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1635                                 d88_sct.c = c;
1636                                 d88_sct.h = h;
1637                                 d88_sct.r = s + 1;
1638                                 d88_sct.n = n;
1639                                 d88_sct.nsec = nsec;
1640                                 d88_sct.dens = 0;
1641                                 d88_sct.del = 0;
1642                                 d88_sct.stat = 0;
1643                                 d88_sct.size = size;
1644                                 
1645                                 // create sector image
1646                                 uint8 dst[16384];
1647                                 memset(dst, 0xe5, sizeof(dst));
1648                                 fi->Fread(dst, size, 1);
1649                                 
1650                                 // copy to d88
1651                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1652                                 COPYBUFFER(dst, size);
1653                                 trkptr += sizeof(d88_sct_t) + size;
1654                         }
1655                 }
1656         }
1657         d88_hdr.size = trkptr;
1658         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1659         return true;
1660 }
1661
1662 #define STATE_VERSION   6
1663
1664 void DISK::save_state(FILEIO* state_fio)
1665 {
1666         state_fio->FputUint32(STATE_VERSION);
1667         
1668         state_fio->Fwrite(buffer, sizeof(buffer), 1);
1669         state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
1670         state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
1671         state_fio->FputUint32(file_size.d);
1672         state_fio->FputInt32(file_bank);
1673         state_fio->FputUint32(crc32);
1674         state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
1675         state_fio->FputBool(inserted);
1676         state_fio->FputBool(ejected);
1677         state_fio->FputBool(write_protected);
1678         state_fio->FputBool(changed);
1679         state_fio->FputUint8(media_type);
1680         state_fio->FputBool(is_solid_image);
1681         state_fio->FputBool(is_fdi_image);
1682         state_fio->FputBool(is_1dd_image);
1683         state_fio->FputInt32(is_special_disk);
1684         state_fio->Fwrite(track, sizeof(track), 1);
1685         state_fio->FputInt32(sector_num.sd);
1686         state_fio->FputBool(invalid_format);
1687         state_fio->FputBool(no_skew);
1688         state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
1689         state_fio->Fwrite(id_position, sizeof(id_position), 1);
1690         state_fio->Fwrite(data_position, sizeof(data_position), 1);
1691         state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
1692         state_fio->FputInt32(sector_size.sd);
1693         state_fio->Fwrite(id, sizeof(id), 1);
1694         state_fio->FputUint8(density);
1695         state_fio->FputBool(deleted);
1696         state_fio->FputBool(addr_crc_error);
1697         state_fio->FputBool(data_crc_error);
1698         state_fio->FputUint8(drive_type);
1699         state_fio->FputInt32(drive_rpm);
1700         state_fio->FputBool(drive_mfm);
1701 }
1702
1703 bool DISK::load_state(FILEIO* state_fio)
1704 {
1705         if(state_fio->FgetUint32() != STATE_VERSION) {
1706                 return false;
1707         }
1708         state_fio->Fread(buffer, sizeof(buffer), 1);
1709         state_fio->Fread(orig_path, sizeof(orig_path), 1);
1710         state_fio->Fread(dest_path, sizeof(dest_path), 1);
1711         file_size.d = state_fio->FgetUint32();
1712         file_bank = state_fio->FgetInt32();
1713         crc32 = state_fio->FgetUint32();
1714         state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
1715         inserted = state_fio->FgetBool();
1716         ejected = state_fio->FgetBool();
1717         write_protected = state_fio->FgetBool();
1718         changed = state_fio->FgetBool();
1719         media_type = state_fio->FgetUint8();
1720         is_solid_image = state_fio->FgetBool();
1721         is_fdi_image = state_fio->FgetBool();
1722         is_1dd_image = state_fio->FgetBool();
1723         is_special_disk = state_fio->FgetInt32();
1724         state_fio->Fread(track, sizeof(track), 1);
1725         sector_num.sd = state_fio->FgetInt32();
1726         invalid_format = state_fio->FgetBool();
1727         no_skew = state_fio->FgetBool();
1728         state_fio->Fread(sync_position, sizeof(sync_position), 1);
1729         state_fio->Fread(id_position, sizeof(id_position), 1);
1730         state_fio->Fread(data_position, sizeof(data_position), 1);
1731         int offset = state_fio->FgetInt32();
1732         sector = (offset != -1) ? buffer + offset : NULL;
1733         sector_size.sd = state_fio->FgetInt32();
1734         state_fio->Fread(id, sizeof(id), 1);
1735         density = state_fio->FgetUint8();
1736         deleted = state_fio->FgetBool();
1737         addr_crc_error = state_fio->FgetBool();
1738         data_crc_error = state_fio->FgetBool();
1739         drive_type = state_fio->FgetUint8();
1740         drive_rpm = state_fio->FgetInt32();
1741         drive_mfm = state_fio->FgetBool();
1742         return true;
1743 }
1744