OSDN Git Service

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