OSDN Git Service

[General] Tracking to upstream, 2015-01-24.
[csp-qt/common_source_project-fm7.git] / source / src / vm / disk.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.09.16-
6
7         [ d88 handler ]
8 */
9
10 #include "disk.h"
11 #include "../fileio.h"
12 #if defined(_USE_AGAR) || defined(_USE_SDL)
13 #include "agar_logger.h"
14 #endif
15
16 // crc table
17 static const uint16 crc_table[256] = {
18         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
19         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
20         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
21         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
22         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
23         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
24         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
25         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
26         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
27         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
28         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
29         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
30         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
31         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
32         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
33         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
34 };
35
36 // teledisk decoder table
37 static const uint8 d_code[256] = {
38         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
41         0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
42         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
43         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
44         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
45         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
46         0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
47         0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
48         0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
49         0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
50         0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
51         0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
52         0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
53         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
54 };
55 static const uint8 d_len[256] = {
56         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
57         0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
58         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
59         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
60         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
61         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
62         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
63         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
64         0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
65         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
66         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
67         0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
68         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
69         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
70         0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
71         0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
72 };
73 static const int secsize[8] = {
74         128, 256, 512, 1024, 2048, 4096, 8192, 16384
75 };
76
77 static uint8 tmp_buffer[DISK_BUFFER_SIZE];
78
79 typedef struct fd_format {
80         int type;
81         int ncyl, nside, nsec, size;
82 } fd_format;
83
84 static const fd_format fd_formats[] = {
85         { MEDIA_TYPE_2D,  40, 1, 16,  256 },    // 1D   160KB
86         { MEDIA_TYPE_2D , 40, 2, 16,  256 },    // 2D   320KB
87 #if defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
88         { MEDIA_TYPE_2DD, 80, 2, 16,  256 },    // 2DD  640KB (MZ-2500)
89 #else
90         { MEDIA_TYPE_2DD, 80, 2,  8,  512 },    // 2DD  640KB
91 #endif
92         { MEDIA_TYPE_2DD, 80, 2,  9,  512 },    // 2DD  720KB
93         { MEDIA_TYPE_2HD, 80, 2, 15,  512 },    // 2HC 1.20MB
94         { MEDIA_TYPE_2HD, 77, 2,  8, 1024 },    // 2HD 1.25MB
95         { MEDIA_TYPE_144, 80, 2, 18,  512 },    // 2HD 1.44MB
96         { MEDIA_TYPE_144, 80, 2, 36,  512 },    // 2ED 2.88MB
97         { -1, 0, 0, 0, 0 },
98 };
99
100 void DISK::open(_TCHAR path[], int offset)
101 {
102         // check current disk image
103         if(inserted) {
104 #if defined(_USE_AGAR) || defined(_USE_SDL)
105            AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);
106 #endif
107            if(_tcsicmp(orig_path, path) == 0 && file_offset == offset) {
108                         return;
109                 }
110                 close();
111         }
112         memset(buffer, 0, sizeof(buffer));
113         media_type = MEDIA_TYPE_UNK;
114         is_standard_image = is_fdi_image = false;
115 #if defined(_USE_AGAR) || defined(_USE_SDL)
116         AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);
117 #endif  
118         // open disk image
119         fi = new FILEIO();
120         if(fi->Fopen(path, FILEIO_READ_BINARY)) {
121                 bool converted = false;
122                 
123                 _tcscpy_s(orig_path, _MAX_PATH, path);
124                 _tcscpy_s(dest_path, _MAX_PATH, path);
125                 _stprintf_s(temp_path, _MAX_PATH, _T("%s.$$$"), path);
126                 temporary = false;
127                 
128                 // check if file protected
129                 write_protected = fi->IsProtected(path);
130                 
131                 // is this d88 format ?
132                 if(check_file_extension(path, _T(".d88")) || check_file_extension(path, _T(".d77")) ||
133                    check_file_extension(path, _T(".D88")) || check_file_extension(path, _T(".D77"))) {
134                         fi->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
135                         file_size = fi->Fgetc();
136                         file_size |= fi->Fgetc() << 8;
137                         file_size |= fi->Fgetc() << 16;
138                         file_size |= fi->Fgetc() << 24;
139                         fi->Fseek(offset, FILEIO_SEEK_SET);
140                         fi->Fread(buffer, file_size, 1);
141                         file_offset = offset;
142                         inserted = changed = true;
143                         goto file_loaded;
144                 }
145                 
146                 fi->Fseek(0, FILEIO_SEEK_END);
147                 file_size = fi->Ftell();
148                 fi->Fseek(0, FILEIO_SEEK_SET);
149                 file_offset = 0;
150                 
151 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
152                 // is this 2d format ?
153                 if(check_file_extension(path, _T(".2d"))) {
154                         if(standard_to_d88(MEDIA_TYPE_2D, 40, 2, 16, 256)) {
155                                 inserted = changed = is_standard_image = true;
156                                 goto file_loaded;
157                         }
158                         fi->Fseek(0, FILEIO_SEEK_SET);
159                 }
160 #endif
161                 
162                 // check image file format
163                 for(int i = 0;; i++) {
164                         const fd_format *p = &fd_formats[i];
165                         if(p->type == -1) {
166                                 break;
167                         }
168                         int len = p->ncyl * p->nside * p->nsec * p->size;
169                         // 4096 bytes: FDI header ???
170                         if(file_size == len || (file_size == (len + 4096) && (len == 655360 || len == 1261568))) {
171                                 if(file_size == len + 4096) {
172                                         is_fdi_image = true;
173                                         fi->Fread(fdi_header, 4096, 1);
174                                 }
175                                 if(standard_to_d88(p->type, p->ncyl, p->nside, p->nsec, p->size)) {
176                                         inserted = changed = is_standard_image = true;
177                                         goto file_loaded;
178                                 }
179                         }
180                 }
181                 if(0 < file_size && file_size <= DISK_BUFFER_SIZE) {
182                         memset(buffer, 0, sizeof(buffer));
183                         fi->Fread(buffer, file_size, 1);
184                         
185                         // check d88 format (temporary)
186                         if(*(uint32 *)(buffer + 0x1c) == file_size) {
187                                 inserted = changed = true;
188                                 goto file_loaded;
189                         }
190                         _stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), path);
191                         
192                         // check file header
193                         try {
194                                 if(memcmp(buffer, "TD", 2) == 0 || memcmp(buffer, "td", 2) == 0) {
195                                         // teledisk image file
196                                         inserted = changed = converted = teledisk_to_d88();
197                                 } else if(memcmp(buffer, "IMD", 3) == 0) {
198                                         // imagedisk image file
199                                         inserted = changed = converted = imagedisk_to_d88();
200                                 } else if(memcmp(buffer, "MV - CPC", 8) == 0) {
201                                         // standard cpdread image file
202                                         inserted = changed = converted = cpdread_to_d88(0);
203                                 } else if(memcmp(buffer, "EXTENDED", 8) == 0) {
204                                         // extended cpdread image file
205                                         inserted = changed = converted = cpdread_to_d88(1);
206                                 }
207                         }
208                         catch(...) {
209                                 // failed to convert the disk image
210 #if defined(_USE_AGAR) || defined(_USE_SDL)
211                                 AGAR_DebugLog(AGAR_LOG_INFO, "EE: disk.cpp : Failed to convert disk image.");
212 #endif
213                         }
214                 }
215 file_loaded:
216                 if(fi->IsOpened()) {
217                         fi->Fclose();
218                 }
219                 if(temporary) {
220                         fi->Remove(temp_path);
221                 }
222                 if(inserted) {
223 #if 0
224                         if(converted) {
225                                 // write image
226                                 FILEIO* fio = new FILEIO();
227                                 if(fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
228                                         fio->Fwrite(buffer, file_size, 1);
229                                         fio->Fclose();
230                                 }
231                                 delete fio;
232                         }
233 #endif
234                         crc32 = getcrc32(buffer, file_size);
235                 }
236                 if(buffer[0x1a] != 0) {
237                         write_protected = true;
238                 }
239                 if(media_type == MEDIA_TYPE_UNK) {
240                         if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
241                                 for(int trkside = 0; trkside < 164; trkside++) {
242                                         uint32 offset = buffer[0x20 + trkside * 4 + 0];
243                                         offset |= buffer[0x20 + trkside * 4 + 1] << 8;
244                                         offset |= buffer[0x20 + trkside * 4 + 2] << 16;
245                                         offset |= buffer[0x20 + trkside * 4 + 3] << 24;
246                                         
247                                         if(!offset) {
248                                                 continue;
249                                         }
250                                         // track found
251                                         uint8 *t = buffer + offset;
252                                         int sector_num = t[4] | (t[5] << 8);
253                                         int data_size = t[14] | (t[15] << 8);
254                                         
255                                         if(sector_num >= 18 && data_size == 512) {
256                                                 media_type = MEDIA_TYPE_144;
257                                         }
258                                         break;
259                                 }
260                         }
261                 }
262                 // FIXME: ugly patch for X1turbo ALPHA and Batten Tanuki
263                 is_alpha = is_batten = false;
264 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
265                 if(media_type == MEDIA_TYPE_2D) {
266                         static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
267                         uint32 offset = buffer[0x20] | (buffer[0x21] << 8) | (buffer[0x22] << 16) | (buffer[0x23] << 24);
268                         uint8 *t = buffer + offset;
269                         is_alpha = (strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0);
270                         is_batten = (memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0);
271                 }
272 #endif
273         }
274         delete fi;
275 }
276
277 void DISK::close()
278 {
279         // write disk image
280         if(inserted) {
281                 if(!write_protected && file_size && getcrc32(buffer, file_size) != crc32) {
282                         // write image
283                         FILEIO* fio = new FILEIO();
284                         if(fio->Fopen(dest_path, FILEIO_READ_WRITE_BINARY)) {
285                                 fio->Fseek(file_offset, FILEIO_SEEK_SET);
286                         } else {
287                                 _TCHAR tmp_path[_MAX_PATH];
288                                 _stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
289                                 fio->Fopen(emu->bios_path(tmp_path), FILEIO_WRITE_BINARY);
290                         }
291                         if(fio->IsOpened()) {
292                                 if(is_standard_image) {
293                                         if(is_fdi_image) {
294                                                 fio->Fwrite(fdi_header, 4096, 1);
295                                         }
296                                         for(int trkside = 0; trkside < 164; trkside++) {
297                                                 uint32 offset = buffer[0x20 + trkside * 4 + 0];
298                                                 offset |= buffer[0x20 + trkside * 4 + 1] << 8;
299                                                 offset |= buffer[0x20 + trkside * 4 + 2] << 16;
300                                                 offset |= buffer[0x20 + trkside * 4 + 3] << 24;
301                                                 
302                                                 if(!offset) {
303                                                         break;
304                                                 }
305                                                 uint8* t = buffer + offset;
306                                                 int sector_num = t[4] | (t[5] << 8);
307                                                 
308                                                 for(int i = 0; i < sector_num; i++) {
309                                                         int data_size = t[14] | (t[15] << 8);
310                                                         fio->Fwrite(t + 0x10, data_size, 1);
311                                                         t += data_size + 0x10;
312                                                 }
313                                         }
314                                 } else {
315                                         fio->Fwrite(buffer, file_size, 1);
316                                 }
317                                 fio->Fclose();
318                         }
319                         delete fio;
320                 }
321                 ejected = true;
322         }
323         inserted = write_protected = false;
324         file_size = 0;
325         sector_size = sector_num = 0;
326         sector = NULL;
327 }
328
329 bool DISK::get_track(int trk, int side)
330 {
331         sector_size = sector_num = 0;
332         no_skew = true;
333         
334         // disk not inserted or invalid media type
335         if(!(inserted && check_media_type())) {
336                 return false;
337         }
338         
339         // search track
340         int trkside = trk * 2 + (side & 1);
341         if(!(0 <= trkside && trkside < 164)) {
342                 return false;
343         }
344         uint32 offset = buffer[0x20 + trkside * 4 + 0];
345         offset |= buffer[0x20 + trkside * 4 + 1] << 8;
346         offset |= buffer[0x20 + trkside * 4 + 2] << 16;
347         offset |= buffer[0x20 + trkside * 4 + 3] << 24;
348         
349         if(!offset) {
350                 return false;
351         }
352         
353         // track found
354         sector = buffer + offset;
355         sector_num = sector[4] | (sector[5] << 8);
356         
357         // create each sector position in track
358         int sync_size  = drive_mfm ? 12 : 6;
359         int am_size = drive_mfm ? 3 : 0;
360         int gap2_size = drive_mfm ? 22 : 11;
361         
362         data_size_shift = 0;
363         too_many_sectors = false;
364 retry:
365         uint8* t = sector;
366         int total = 0, gap3_size;
367         
368         for(int i = 0; i < sector_num; i++) {
369                 int data_size = t[14] | (t[15] << 8);
370                 
371                 if((data_size >> data_size_shift) < 0x80) {
372                         too_many_sectors = true;
373                         break;
374                 }
375                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size + sync_size + (am_size + 1);
376                 total += (data_size >> data_size_shift) + 2;
377                 
378                 t += data_size + 0x10;
379         }
380         if(too_many_sectors) {
381                 // Too many sectors in this track
382                 gap3_size = 32;
383                 data_size_shift = 0;
384         } else if((gap3_size = (get_track_size() - total) / (sector_num + 2)) < 12) {
385                 // ID:N is modified
386                 data_size_shift++;
387                 goto retry;
388         }
389         t = sector;
390         total = gap3_size * 2;
391         
392         for(int i = 0; i < sector_num; i++) {
393                 int data_size = t[14] | (t[15] << 8);
394                 
395                 if(too_many_sectors) {
396                         total = gap3_size * 2 + (get_track_size() - gap3_size * 2) * i / sector_num;
397                 }
398                 sync_position[i] = total;
399                 total += sync_size + (am_size + 1);
400                 id_position[i] = total;
401                 total += (4 + 2) + gap2_size + sync_size + (am_size + 1);
402                 data_position[i] = total;
403                 total += (data_size >> data_size_shift) + 2 + gap3_size;
404                 
405                 if(t[2] != i + 1) {
406                         no_skew = false;
407                 }
408                 t += data_size + 0x10;
409         }
410         return true;
411 }
412
413 bool DISK::make_track(int trk, int side)
414 {
415         int track_size = get_track_size();
416         
417         if(!get_track(trk, side)) {
418                 // create a dummy track
419                 for(int i = 0; i < track_size; i++) {
420                         track[i] = rand();
421                 }
422                 return false;
423         }
424         
425         // make track image
426         int sync_size  = drive_mfm ? 12 : 6;
427         int am_size = drive_mfm ? 3 : 0;
428         int gap2_size = drive_mfm ? 22 : 11;
429         uint8 gap_data = drive_mfm ? 0x4e : 0xff;
430         
431         // preamble
432         memset(track, gap_data, track_size);
433         
434         if(sync_position[0] >= (sync_size + am_size + 1) + (8 + 5)) {
435                 int p = (sync_position[0] - (sync_size + am_size + 1)) * 8 / (8 + 5);
436                 
437                 // sync
438                 for(int i = 0; i < sync_size; i++) {
439                         track[p++] = 0x00;
440                 }
441                 // index mark
442                 for(int i = 0; i < am_size; i++) {
443                         track[p++] = 0xc2;
444                 }
445                 track[p++] = 0xfc;
446         }
447         
448         // sectors
449         uint8 *t = sector;
450         
451         for(int i = 0; i < sector_num; i++) {
452                 int data_size = t[14] | (t[15] << 8);
453                 int p = sync_position[i];
454                 
455                 // sync
456                 for(int j = 0; j < sync_size; j++) {
457                         if(p < track_size) track[p++] = 0x00;
458                 }
459                 // am1
460                 for(int j = 0; j < am_size; j++) {
461                         if(p < track_size) track[p++] = 0xa1;
462                 }
463                 if(p < track_size) track[p++] = 0xfe;
464                 // id
465                 if(p < track_size) track[p++] = t[0];
466                 if(p < track_size) track[p++] = t[1];
467                 if(p < track_size) track[p++] = t[2];
468                 if(p < track_size) track[p++] = t[3];
469                 uint16 crc = 0;
470                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
471                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
472                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
473                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
474                 if(p < track_size) track[p++] = crc >> 8;
475                 if(p < track_size) track[p++] = crc & 0xff;
476                 // gap2
477                 for(int j = 0; j < gap2_size; j++) {
478                         if(p < track_size) track[p++] = gap_data;
479                 }
480                 // sync
481                 for(int j = 0; j < sync_size; j++) {
482                         if(p < track_size) track[p++] = 0x00;
483                 }
484                 // am2
485                 for(int j = 0; j < am_size; j++) {
486                         if(p < track_size) track[p++] = 0xa1;
487                 }
488                 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
489                 // data
490                 crc = 0;
491                 for(int j = 0; j < (data_size >> data_size_shift); j++) {
492                         if(p < track_size) track[p++] = t[0x10 + j];
493                         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
494                 }
495                 if(p < track_size) track[p++] = crc >> 8;
496                 if(p < track_size) track[p++] = crc & 0xff;
497                 
498                 t += data_size + 0x10;
499         }
500         return true;
501 }
502
503 bool DISK::get_sector(int trk, int side, int index)
504 {
505         sector_size = sector_num = 0;
506         sector = NULL;
507         
508         // disk not inserted or invalid media type
509         if(!(inserted && check_media_type())) {
510                 return false;
511         }
512         
513         // search track
514         int trkside = trk * 2 + (side & 1);
515         if(!(0 <= trkside && trkside < 164)) {
516                 return false;
517         }
518         uint32 offset = buffer[0x20 + trkside * 4 + 0];
519         offset |= buffer[0x20 + trkside * 4 + 1] << 8;
520         offset |= buffer[0x20 + trkside * 4 + 2] << 16;
521         offset |= buffer[0x20 + trkside * 4 + 3] << 24;
522         
523         if(!offset) {
524                 return false;
525         }
526         
527         // track found
528         uint8* t = buffer + offset;
529         sector_num = t[4] | (t[5] << 8);
530         
531         if(index >= sector_num) {
532                 return false;
533         }
534         
535         // skip sector
536         for(int i = 0; i < index; i++) {
537                 t += (t[14] | (t[15] << 8)) + 0x10;
538         }
539         
540         // header info
541         id[0] = t[0];
542         id[1] = t[1];
543         id[2] = t[2];
544         id[3] = t[3];
545         uint16 crc = 0;
546         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
547         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
548         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
549         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
550         id[4] = crc >> 8;
551         id[5] = crc & 0xff;
552         density = t[6];
553         deleted = t[7];
554         status = t[8];
555         sector = t + 0x10;
556         sector_size = t[14] | (t[15] << 8);
557         
558         return true;
559 }
560
561 int DISK::get_rpm()
562 {
563         if(drive_rpm != 0) {
564                 return drive_rpm;
565         } else if(inserted) {
566                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
567         } else {
568                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
569         }
570 }
571
572 int DISK::get_track_size()
573 {
574         if(inserted) {
575                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
576         } else {
577                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
578         }
579 }
580
581 double DISK::get_usec_per_bytes(int bytes)
582 {
583         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
584 }
585
586 bool DISK::check_media_type()
587 {
588         switch(drive_type) {
589         case DRIVE_TYPE_2D:
590                 return (media_type == MEDIA_TYPE_2D);
591         case DRIVE_TYPE_2DD:
592                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
593         case DRIVE_TYPE_2HD:
594                 return (media_type == MEDIA_TYPE_2HD);
595         case DRIVE_TYPE_144:
596                 return (media_type == MEDIA_TYPE_144);
597         case DRIVE_TYPE_UNK:
598                 return true; // always okay
599         }
600         return false;
601 }
602
603 // teledisk image decoder
604
605 /*
606         this teledisk image decoder is based on:
607         
608                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
609                 LZSS coded by Haruhiko OKUMURA
610                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
611                 Edited and translated to English by Kenji RIKITAKE
612                 TDLZHUF.C by WTK
613 */
614
615 #define COPYBUFFER(src, size) { \
616         if(file_size + (size) > DISK_BUFFER_SIZE) { \
617                 return false; \
618         } \
619         memcpy(buffer + file_size, (src), (size)); \
620         file_size += (size); \
621 }
622
623 bool DISK::teledisk_to_d88()
624 {
625         struct td_hdr_t hdr;
626         struct td_cmt_t cmt;
627         struct td_trk_t trk;
628         struct td_sct_t sct;
629         struct d88_hdr_t d88_hdr;
630         struct d88_sct_t d88_sct;
631         uint8 obuf[512];
632         
633         // check teledisk header
634         fi->Fseek(0, FILEIO_SEEK_SET);
635         fi->Fread(&hdr, sizeof(td_hdr_t), 1);
636         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
637                 // decompress to the temporary file
638                 FILEIO* fo = new FILEIO();
639                 if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {
640                         delete fo;
641                         return false;
642                 }
643                 int rd = 1;
644                 init_decode();
645                 do {
646                         if((rd = decode(obuf, 512)) > 0) {
647                                 fo->Fwrite(obuf, rd, 1);
648                         }
649                 }
650                 while(rd > 0);
651                 fo->Fclose();
652                 delete fo;
653                 temporary = true;
654                 
655                 // reopen the temporary file
656                 fi->Fclose();
657                 if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {
658                         return false;
659                 }
660         }
661         if(hdr.flag & 0x80) {
662                 // skip comment
663                 fi->Fread(&cmt, sizeof(td_cmt_t), 1);
664                 fi->Fseek(cmt.len, FILEIO_SEEK_CUR);
665         }
666         
667         // create d88 image
668         file_size = 0;
669         
670         // create d88 header
671         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
672         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
673         d88_hdr.protect = 0; // non-protected
674         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
675         
676         // create tracks
677         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
678         fi->Fread(&trk, sizeof(td_trk_t), 1);
679         while(trk.nsec != 0xff) {
680                 d88_hdr.trkptr[trkcnt++] = trkptr;
681                 if(hdr.sides == 1) {
682                         d88_hdr.trkptr[trkcnt++] = trkptr;
683                 }
684                 
685                 // read sectors in this track
686                 for(int i = 0; i < trk.nsec; i++) {
687                         uint8 buf[2048], dst[2048];
688                         memset(buf, 0, sizeof(buf));
689                         memset(dst, 0, sizeof(dst));
690                         
691                         // read sector header
692                         fi->Fread(&sct, sizeof(td_sct_t), 1);
693                         
694                         // create d88 sector header
695                         memset(&d88_sct, 0, sizeof(d88_sct_t));
696                         d88_sct.c = sct.c;
697                         d88_sct.h = sct.h;
698                         d88_sct.r = sct.r;
699                         d88_sct.n = sct.n;
700                         d88_sct.nsec = trk.nsec;
701                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
702                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
703                         d88_sct.stat = (sct.ctrl & 2) ? 0x10 : 0; // crc?
704                         d88_sct.size = secsize[sct.n & 3];
705                         
706                         // create sector image
707                         if(sct.ctrl != 0x10) {
708                                 // read sector source
709                                 int len = fi->Fgetc();
710                                 len += fi->Fgetc() * 256 - 1;
711                                 int flag = fi->Fgetc(), d = 0;
712                                 fi->Fread(buf, len, 1);
713                                 
714                                 // convert
715                                 if(flag == 0) {
716                                         memcpy(dst, buf, len);
717                                 } else if(flag == 1) {
718                                         int len2 = buf[0] | (buf[1] << 8);
719                                         while(len2--) {
720                                                 dst[d++] = buf[2];
721                                                 dst[d++] = buf[3];
722                                         }
723                                 } else if(flag == 2) {
724                                         for(int s = 0; s < len;) {
725                                                 int type = buf[s++];
726                                                 int len2 = buf[s++];
727                                                 if(type == 0) {
728                                                         while(len2--) {
729                                                                 dst[d++] = buf[s++];
730                                                         }
731                                                 } else if(type < 5) {
732                                                         uint8 pat[256];
733                                                         int n = 2;
734                                                         while(type-- > 1) {
735                                                                 n *= 2;
736                                                         }
737                                                         for(int j = 0; j < n; j++) {
738                                                                 pat[j] = buf[s++];
739                                                         }
740                                                         while(len2--) {
741                                                                 for(int j = 0; j < n; j++) {
742                                                                         dst[d++] = pat[j];
743                                                                 }
744                                                         }
745                                                 } else {
746                                                         break; // unknown type
747                                                 }
748                                         }
749                                 } else {
750                                         break; // unknown flag
751                                 }
752                         } else {
753                                 d88_sct.size = 0;
754                         }
755                         
756                         // copy to d88
757                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
758                         COPYBUFFER(dst, d88_sct.size);
759                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
760                 }
761                 // read next track
762                 fi->Fread(&trk, sizeof(td_trk_t), 1);
763         }
764         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
765         d88_hdr.size = trkptr;
766         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
767         return true;
768 }
769
770 int DISK::next_word()
771 {
772         if(ibufndx >= ibufcnt) {
773                 ibufndx = ibufcnt = 0;
774                 memset(inbuf, 0, 512);
775                 for(int i = 0; i < 512; i++) {
776                         int d = fi->Fgetc();
777                         if(d == EOF) {
778                                 if(i) {
779                                         break;
780                                 }
781                                 return(-1);
782                         }
783                         inbuf[i] = d;
784                         ibufcnt = i + 1;
785                 }
786         }
787         while(getlen <= 8) {
788                 getbuf |= inbuf[ibufndx++] << (8 - getlen);
789                 getlen += 8;
790         }
791         return 0;
792 }
793
794 int DISK::get_bit()
795 {
796         if(next_word() < 0) {
797                 return -1;
798         }
799         short i = getbuf;
800         getbuf <<= 1;
801         getlen--;
802         return (i < 0) ? 1 : 0;
803 }
804
805 int DISK::get_byte()
806 {
807         if(next_word() != 0) {
808                 return -1;
809         }
810         uint16 i = getbuf;
811         getbuf <<= 8;
812         getlen -= 8;
813         i >>= 8;
814         return (int)i;
815 }
816
817 void DISK::start_huff()
818 {
819         int i, j;
820         for(i = 0; i < N_CHAR; i++) {
821                 freq[i] = 1;
822                 son[i] = i + TABLE_SIZE;
823                 prnt[i + TABLE_SIZE] = i;
824         }
825         i = 0; j = N_CHAR;
826         while(j <= ROOT_POSITION) {
827                 freq[j] = freq[i] + freq[i + 1];
828                 son[j] = i;
829                 prnt[i] = prnt[i + 1] = j;
830                 i += 2; j++;
831         }
832         freq[TABLE_SIZE] = 0xffff;
833         prnt[ROOT_POSITION] = 0;
834 }
835
836 void DISK::reconst()
837 {
838         short i, j = 0, k;
839         uint16 f, l;
840         for(i = 0; i < TABLE_SIZE; i++) {
841                 if(son[i] >= TABLE_SIZE) {
842                         freq[j] = (freq[i] + 1) / 2;
843                         son[j] = son[i];
844                         j++;
845                 }
846         }
847         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
848                 k = i + 1;
849                 f = freq[j] = freq[i] + freq[k];
850                 for(k = j - 1; f < freq[k]; k--);
851                 k++;
852                 l = (j - k) * 2;
853                 memmove(&freq[k + 1], &freq[k], l);
854                 freq[k] = f;
855                 memmove(&son[k + 1], &son[k], l);
856                 son[k] = i;
857         }
858         for(i = 0; i < TABLE_SIZE; i++) {
859                 if((k = son[i]) >= TABLE_SIZE) {
860                         prnt[k] = i;
861                 } else {
862                         prnt[k] = prnt[k + 1] = i;
863                 }
864         }
865 }
866
867 void DISK::update(int c)
868 {
869         int i, j, k, l;
870         if(freq[ROOT_POSITION] == MAX_FREQ) {
871                 reconst();
872         }
873         c = prnt[c + TABLE_SIZE];
874         do {
875                 k = ++freq[c];
876                 if(k > freq[l = c + 1]) {
877                         while(k > freq[++l]);
878                         l--;
879                         freq[c] = freq[l];
880                         freq[l] = k;
881                         i = son[c];
882                         prnt[i] = l;
883                         if(i < TABLE_SIZE) {
884                                 prnt[i + 1] = l;
885                         }
886                         j = son[l];
887                         son[l] = i;
888                         prnt[j] = c;
889                         if(j < TABLE_SIZE) {
890                                 prnt[j + 1] = c;
891                         }
892                         son[c] = j;
893                         c = l;
894                 }
895         }
896         while((c = prnt[c]) != 0);
897 }
898
899 short DISK::decode_char()
900 {
901         int ret;
902         uint16 c = son[ROOT_POSITION];
903         while(c < TABLE_SIZE) {
904                 if((ret = get_bit()) < 0) {
905                         return -1;
906                 }
907                 c += (unsigned)ret;
908                 c = son[c];
909         }
910         c -= TABLE_SIZE;
911         update(c);
912         return c;
913 }
914
915 short DISK::decode_position()
916 {
917         short bit;
918         uint16 i, j, c;
919         if((bit = get_byte()) < 0) {
920                 return -1;
921         }
922         i = (uint16)bit;
923         c = (uint16)d_code[i] << 6;
924         j = d_len[i] - 2;
925         while(j--) {
926                 if((bit = get_bit()) < 0) {
927                          return -1;
928                 }
929                 i = (i << 1) + bit;
930         }
931         return (c | i & 0x3f);
932 }
933
934 void DISK::init_decode()
935 {
936         ibufcnt= ibufndx = bufcnt = getbuf = 0;
937         getlen = 0;
938         start_huff();
939         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
940                 text_buf[i] = ' ';
941         }
942         ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
943 }
944
945 int DISK::decode(uint8 *buf, int len)
946 {
947         short c, pos;
948         int  count;
949         for(count = 0; count < len;) {
950                 if(bufcnt == 0) {
951                         if((c = decode_char()) < 0) {
952                                 return count;
953                         }
954                         if(c < 256) {
955                                 *(buf++) = (uint8)c;
956                                 text_buf[ptr++] = (uint8)c;
957                                 ptr &= (STRING_BUFFER_SIZE - 1);
958                                 count++;
959                         } else {
960                                 if((pos = decode_position()) < 0) {
961                                         return count;
962                                 }
963                                 bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
964                                 bufcnt = c - 255 + THRESHOLD;
965                                 bufndx = 0;
966                         }
967                 } else {
968                         while(bufndx < bufcnt && count < len) {
969                                 c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];
970                                 *(buf++) = (uint8)c;
971                                 bufndx++;
972                                 text_buf[ptr++] = (uint8)c;
973                                 ptr &= (STRING_BUFFER_SIZE - 1);
974                                 count++;
975                         }
976                         if(bufndx >= bufcnt) {
977                                 bufndx = bufcnt = 0;
978                         }
979                 }
980         }
981         return count;
982 }
983
984 // imagedisk image decoder
985
986 bool DISK::imagedisk_to_d88()
987 {
988         struct imd_trk_t trk;
989         struct d88_hdr_t d88_hdr;
990         struct d88_sct_t d88_sct;
991         
992         // skip comment
993         fi->Fseek(0, FILEIO_SEEK_SET);
994         int tmp;
995         while((tmp = fi->Fgetc()) != 0x1a) {
996                 if(tmp == EOF) {
997                         return false;
998                 }
999         }
1000         
1001         // create d88 image
1002         file_size = 0;
1003         
1004         // create d88 header
1005         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1006         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1007         d88_hdr.protect = 0; // non-protected
1008         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1009         
1010         // create tracks
1011         int trkptr = sizeof(d88_hdr_t);
1012         int trkcnt = 0, mode;
1013         
1014         for(int t = 0; t < 164; t++) {
1015                 // check end of file
1016                 if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {
1017                         break;
1018                 }
1019                 trkcnt = t;
1020                 
1021                 // check track header
1022                 if(t == 0) {
1023                         mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps
1024                 }
1025                 if(!trk.nsec) {
1026                         continue;
1027                 }
1028                 d88_hdr.trkptr[t] = trkptr;
1029                 
1030                 // setup sector id
1031                 uint8 c[64], h[64], r[64];
1032                 fi->Fread(r, trk.nsec, 1);
1033                 if(trk.head & 0x80) {
1034                         fi->Fread(c, trk.nsec, 1);
1035                 } else {
1036                         memset(c, trk.cyl, sizeof(c));
1037                 }
1038                 if(trk.head & 0x40) {
1039                         fi->Fread(h, trk.nsec, 1);
1040                 } else {
1041                         memset(h, trk.head & 1, sizeof(h));
1042                 }
1043                 
1044                 // read sectors in this track
1045                 for(int i = 0; i < trk.nsec; i++) {
1046                         // create d88 sector header
1047                         static const uint8 del[] = {0, 0, 0, 0x10, 0x10, 0, 0, 0x10, 0x10};
1048                         static const uint8 err[] = {0, 0, 0, 0, 0, 0x10, 0x10, 0x10, 0x10};
1049                         int sectype = fi->Fgetc();
1050                         if(sectype > 8) {
1051                                 return false;
1052                         }
1053                         memset(&d88_sct, 0, sizeof(d88_sct_t));
1054                         d88_sct.c = c[i];
1055                         d88_sct.h = h[i];
1056                         d88_sct.r = r[i];
1057                         d88_sct.n = trk.size;
1058                         d88_sct.nsec = trk.nsec;
1059                         d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;
1060                         d88_sct.del = del[sectype];
1061                         d88_sct.stat = err[sectype];
1062                         d88_sct.size = secsize[trk.size & 7];
1063                         
1064                         // create sector image
1065                         uint8 dst[8192];
1066                         if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {
1067                                 // uncompressed
1068                                 fi->Fread(dst, d88_sct.size, 1);
1069                         } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {
1070                                 // compressed
1071                                 int tmp = fi->Fgetc();
1072                                 memset(dst, tmp, d88_sct.size);
1073                         } else {
1074                                 d88_sct.size = 0;
1075                         }
1076                         
1077                         // copy to d88
1078                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1079                         COPYBUFFER(dst, d88_sct.size);
1080                         trkptr += sizeof(d88_sct_t) + d88_sct.size;
1081                 }
1082         }
1083         d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1084         d88_hdr.size = trkptr;
1085         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1086         return true;
1087 }
1088
1089 // cpdread image decoder (from MESS formats/dsk_dsk.c)
1090
1091 bool DISK::cpdread_to_d88(int extended)
1092 {
1093         struct d88_hdr_t d88_hdr;
1094         struct d88_sct_t d88_sct;
1095         int total = 0;
1096         
1097         // get cylinder number and side number
1098         memcpy(tmp_buffer, buffer, file_size);
1099         int ncyl = tmp_buffer[0x30];
1100         int nside = tmp_buffer[0x31];
1101         
1102         // create d88 image
1103         file_size = 0;
1104         
1105         // create d88 header
1106         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1107         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDRead");
1108         d88_hdr.protect = 0; // non-protected
1109         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1110         
1111         // create tracks
1112         int trkofs = 0x100, trkofs_ptr = 0x34;
1113         int trkptr = sizeof(d88_hdr_t);
1114         
1115         for(int c = 0; c < ncyl; c++) {
1116                 for(int h = 0; h < nside; h++) {
1117                         // read sectors in this track
1118                         uint8 *track_info = tmp_buffer + trkofs;
1119                         int cyl = track_info[0x10];
1120                         int side = track_info[0x11];
1121                         int nsec = track_info[0x15];
1122                         int size = 1 << (track_info[0x14] + 7); // standard
1123                         int sctofs = trkofs + 0x100;
1124                         
1125                         if(nside == 1) {
1126                                 // double side
1127                                 d88_hdr.trkptr[2 * cyl] = d88_hdr.trkptr[2 * cyl + 1] = trkptr;
1128                         } else {
1129                                 d88_hdr.trkptr[2 * cyl + side] = trkptr;
1130                         }
1131                         for(int s = 0; s < nsec; s++) {
1132                                 // get sector size
1133                                 uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;
1134                                 if(extended) {
1135                                         size = sector_info[6] + sector_info[7] * 256;
1136                                 }
1137                                 
1138                                 // create d88 sector header
1139                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1140                                 d88_sct.c = sector_info[0];
1141                                 d88_sct.h = sector_info[1];
1142                                 d88_sct.r = sector_info[2];
1143                                 d88_sct.n = sector_info[3];
1144                                 d88_sct.nsec = nsec;
1145                                 d88_sct.dens = 0;
1146                                 d88_sct.del = (sector_info[5] & 0x40) ? 0x10 : 0;
1147                                 d88_sct.stat = 0;
1148                                 d88_sct.size = size;
1149                                 
1150                                 // copy to d88
1151                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1152                                 COPYBUFFER(tmp_buffer + sctofs, size);
1153                                 trkptr += sizeof(d88_sct_t) + size;
1154                                 sctofs += size;
1155                                 total += size;
1156                         }
1157                         
1158                         if(extended) {
1159                                 trkofs += tmp_buffer[trkofs_ptr++] * 256;
1160                         } else {
1161                                 trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1162                         }
1163                 }
1164         }
1165         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1166         d88_hdr.size = trkptr;
1167         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1168         return true;
1169 }
1170
1171 // standard image decoder
1172
1173 bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size)
1174 {
1175         struct d88_hdr_t d88_hdr;
1176         struct d88_sct_t d88_sct;
1177         int n = 0, t = 0;
1178         
1179         file_size = 0;
1180         
1181         // create d88 header
1182         memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1183         _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "STANDARD");
1184         d88_hdr.protect = 0; // non-protected
1185         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
1186         media_type = type;
1187         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1188         
1189         // sector length
1190         for(int i = 0; i < 8; i++) {
1191                 if(size == (128 << i)) {
1192                         n = i;
1193                         break;
1194                 }
1195         }
1196         
1197         // create tracks
1198         int trkptr = sizeof(d88_hdr_t);
1199         for(int c = 0; c < ncyl; c++) {
1200                 for(int h = 0; h < nside; h++) {
1201                         d88_hdr.trkptr[t++] = trkptr;
1202                         if(nside == 1) {
1203                                 // double side
1204                                 d88_hdr.trkptr[t++] = trkptr;
1205                         }
1206                         
1207                         // read sectors in this track
1208                         for(int s = 0; s < nsec; s++) {
1209                                 // create d88 sector header
1210                                 memset(&d88_sct, 0, sizeof(d88_sct_t));
1211                                 d88_sct.c = c;
1212                                 d88_sct.h = h;
1213                                 d88_sct.r = s + 1;
1214                                 d88_sct.n = n;
1215                                 d88_sct.nsec = nsec;
1216                                 d88_sct.dens = 0;
1217                                 d88_sct.del = 0;
1218                                 d88_sct.stat = 0;
1219                                 d88_sct.size = size;
1220                                 
1221                                 // create sector image
1222                                 uint8 dst[16384];
1223                                 memset(dst, 0xe5, sizeof(dst));
1224                                 fi->Fread(dst, size, 1);
1225                                 
1226                                 // copy to d88
1227                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1228                                 COPYBUFFER(dst, size);
1229                                 trkptr += sizeof(d88_sct_t) + size;
1230                         }
1231                 }
1232         }
1233         d88_hdr.size = trkptr;
1234         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1235         return true;
1236 }
1237
1238 #define STATE_VERSION   1
1239
1240 void DISK::save_state(FILEIO* state_fio)
1241 {
1242         state_fio->FputUint32(STATE_VERSION);
1243         
1244         state_fio->Fwrite(buffer, sizeof(buffer), 1);
1245         state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
1246         state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
1247         state_fio->FputInt32(file_size);
1248         state_fio->FputInt32(file_offset);
1249         state_fio->FputUint32(crc32);
1250         state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
1251         state_fio->FputBool(inserted);
1252         state_fio->FputBool(ejected);
1253         state_fio->FputBool(write_protected);
1254         state_fio->FputBool(changed);
1255         state_fio->FputUint8(media_type);
1256         state_fio->FputBool(is_standard_image);
1257         state_fio->FputBool(is_fdi_image);
1258 #if 0
1259         state_fio->FputBool(is_alpha);
1260         state_fio->FputBool(is_batten);
1261 #else
1262         // this is to keep the state version
1263         state_fio->FputUint8((is_alpha ? 1 : 0) | (is_batten ? 2 : 0));
1264 #endif
1265         state_fio->Fwrite(track, sizeof(track), 1);
1266         state_fio->FputInt32(sector_num);
1267         state_fio->FputInt32(data_size_shift);
1268         state_fio->FputBool(too_many_sectors);
1269         state_fio->FputBool(no_skew);
1270         state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
1271         state_fio->Fwrite(id_position, sizeof(id_position), 1);
1272         state_fio->Fwrite(data_position, sizeof(data_position), 1);
1273         state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
1274         state_fio->FputInt32(sector_size);
1275         state_fio->Fwrite(id, sizeof(id), 1);
1276         state_fio->FputUint8(density);
1277         state_fio->FputUint8(deleted);
1278         state_fio->FputUint8(status);
1279         state_fio->FputUint8(drive_type);
1280         state_fio->FputInt32(drive_rpm);
1281         state_fio->FputBool(drive_mfm);
1282 }
1283
1284 bool DISK::load_state(FILEIO* state_fio)
1285 {
1286         if(state_fio->FgetUint32() != STATE_VERSION) {
1287                 return false;
1288         }
1289         state_fio->Fread(buffer, sizeof(buffer), 1);
1290         state_fio->Fread(orig_path, sizeof(orig_path), 1);
1291         state_fio->Fread(dest_path, sizeof(dest_path), 1);
1292         file_size = state_fio->FgetInt32();
1293         file_offset = state_fio->FgetInt32();
1294         crc32 = state_fio->FgetUint32();
1295         state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
1296         inserted = state_fio->FgetBool();
1297         ejected = state_fio->FgetBool();
1298         write_protected = state_fio->FgetBool();
1299         changed = state_fio->FgetBool();
1300         media_type = state_fio->FgetUint8();
1301         is_standard_image = state_fio->FgetBool();
1302         is_fdi_image = state_fio->FgetBool();
1303 #if 0
1304         is_alpha = state_fio->FgetBool();
1305         is_batten = state_fio->FgetBool();
1306 #else
1307         // this is to keep the state version
1308         uint8 tmp = state_fio->FgetUint8();
1309         is_alpha = ((tmp & 1) != 0);
1310         is_batten = ((tmp & 2) != 0);
1311 #endif
1312         state_fio->Fread(track, sizeof(track), 1);
1313         sector_num = state_fio->FgetInt32();
1314         data_size_shift = state_fio->FgetInt32();
1315         too_many_sectors = state_fio->FgetBool();
1316         no_skew = state_fio->FgetBool();
1317         state_fio->Fread(sync_position, sizeof(sync_position), 1);
1318         state_fio->Fread(id_position, sizeof(id_position), 1);
1319         state_fio->Fread(data_position, sizeof(data_position), 1);
1320         int offset = state_fio->FgetInt32();
1321         sector = (offset != -1) ? buffer + offset : NULL;
1322         sector_size = state_fio->FgetInt32();
1323         state_fio->Fread(id, sizeof(id), 1);
1324         density = state_fio->FgetUint8();
1325         deleted = state_fio->FgetUint8();
1326         status = state_fio->FgetUint8();
1327         drive_type = state_fio->FgetUint8();
1328         drive_rpm = state_fio->FgetInt32();
1329         drive_mfm = state_fio->FgetBool();
1330         return true;
1331 }
1332