OSDN Git Service

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