OSDN Git Service

[INITIAL] Import 20141226 version of http://homepage3.nifty.com/takeda-toshiya/common...
[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                 if(_tcsicmp(orig_path, path) == 0 && file_offset == offset) {\r
120                         return;\r
121                 }\r
122                 close();\r
123         }\r
124         memset(buffer, 0, sizeof(buffer));\r
125         media_type = MEDIA_TYPE_UNK;\r
126         is_standard_image = is_fdi_image = false;\r
127         \r
128         // open disk image\r
129         fi = new FILEIO();\r
130         if(fi->Fopen(path, FILEIO_READ_BINARY)) {\r
131                 bool converted = false;\r
132                 \r
133                 _tcscpy(orig_path, path);\r
134                 _tcscpy(dest_path, path);\r
135                 _stprintf(temp_path, _T("%s.$$$"), path);\r
136                 temporary = false;\r
137                 \r
138                 // check if file protected\r
139                 write_protected = fi->IsProtected(path);\r
140                 \r
141                 // is this d88 format ?\r
142                 if(check_file_extension(path, _T(".d88")) || check_file_extension(path, _T(".d77"))) {\r
143                         fi->Fseek(offset + 0x1c, FILEIO_SEEK_SET);\r
144                         file_size = fi->Fgetc();\r
145                         file_size |= fi->Fgetc() << 8;\r
146                         file_size |= fi->Fgetc() << 16;\r
147                         file_size |= fi->Fgetc() << 24;\r
148                         fi->Fseek(offset, FILEIO_SEEK_SET);\r
149                         fi->Fread(buffer, file_size, 1);\r
150                         file_offset = offset;\r
151                         inserted = changed = true;\r
152                         goto file_loaded;\r
153                 }\r
154                 \r
155                 fi->Fseek(0, FILEIO_SEEK_END);\r
156                 file_size = fi->Ftell();\r
157                 fi->Fseek(0, FILEIO_SEEK_SET);\r
158                 file_offset = 0;\r
159                 \r
160 #if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)\r
161                 // is this 2d format ?\r
162                 if(check_file_extension(path, _T(".2d"))) {\r
163                         if(standard_to_d88(MEDIA_TYPE_2D, 40, 2, 16, 256)) {\r
164                                 inserted = changed = is_standard_image = true;\r
165                                 goto file_loaded;\r
166                         }\r
167                         fi->Fseek(0, FILEIO_SEEK_SET);\r
168                 }\r
169 #endif\r
170                 \r
171                 // check image file format\r
172                 for(int i = 0;; i++) {\r
173                         const fd_format *p = &fd_formats[i];\r
174                         if(p->type == -1) {\r
175                                 break;\r
176                         }\r
177                         int len = p->ncyl * p->nside * p->nsec * p->size;\r
178                         // 4096 bytes: FDI header ???\r
179                         if(file_size == len || (file_size == (len + 4096) && (len == 655360 || len == 1261568))) {\r
180                                 if(file_size == len + 4096) {\r
181                                         is_fdi_image = true;\r
182                                         fi->Fread(fdi_header, 4096, 1);\r
183                                 }\r
184                                 if(standard_to_d88(p->type, p->ncyl, p->nside, p->nsec, p->size)) {\r
185                                         inserted = changed = is_standard_image = true;\r
186                                         goto file_loaded;\r
187                                 }\r
188                         }\r
189                 }\r
190                 if(0 < file_size && file_size <= DISK_BUFFER_SIZE) {\r
191                         memset(buffer, 0, sizeof(buffer));\r
192                         fi->Fread(buffer, file_size, 1);\r
193                         \r
194                         // check d88 format (temporary)\r
195                         if(*(uint32 *)(buffer + 0x1c) == file_size) {\r
196                                 inserted = changed = true;\r
197                                 goto file_loaded;\r
198                         }\r
199                         _stprintf(dest_path, _T("%s.D88"), path);\r
200                         \r
201                         // check file header\r
202                         try {\r
203                                 if(memcmp(buffer, "TD", 2) == 0 || memcmp(buffer, "td", 2) == 0) {\r
204                                         // teledisk image file\r
205                                         inserted = changed = converted = teledisk_to_d88();\r
206                                 } else if(memcmp(buffer, "IMD", 3) == 0) {\r
207                                         // imagedisk image file\r
208                                         inserted = changed = converted = imagedisk_to_d88();\r
209                                 } else if(memcmp(buffer, "MV - CPC", 8) == 0) {\r
210                                         // standard cpdread image file\r
211                                         inserted = changed = converted = cpdread_to_d88(0);\r
212                                 } else if(memcmp(buffer, "EXTENDED", 8) == 0) {\r
213                                         // extended cpdread image file\r
214                                         inserted = changed = converted = cpdread_to_d88(1);\r
215                                 }\r
216                         }\r
217                         catch(...) {\r
218                                 // failed to convert the disk image\r
219                         }\r
220                 }\r
221 file_loaded:\r
222                 if(fi->IsOpened()) {\r
223                         fi->Fclose();\r
224                 }\r
225                 if(temporary) {\r
226                         fi->Remove(temp_path);\r
227                 }\r
228                 if(inserted) {\r
229 #if 0\r
230                         if(converted) {\r
231                                 // write image\r
232                                 FILEIO* fio = new FILEIO();\r
233                                 if(fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {\r
234                                         fio->Fwrite(buffer, file_size, 1);\r
235                                         fio->Fclose();\r
236                                 }\r
237                                 delete fio;\r
238                         }\r
239 #endif\r
240                         crc32 = getcrc32(buffer, file_size);\r
241                 }\r
242                 if(buffer[0x1a] != 0) {\r
243                         write_protected = true;\r
244                 }\r
245                 if(media_type == MEDIA_TYPE_UNK) {\r
246                         if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {\r
247                                 for(int trkside = 0; trkside < 164; trkside++) {\r
248                                         uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
249                                         offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
250                                         offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
251                                         offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
252                                         \r
253                                         if(!offset) {\r
254                                                 continue;\r
255                                         }\r
256                                         // track found\r
257                                         uint8 *t = buffer + offset;\r
258                                         int sector_num = t[4] | (t[5] << 8);\r
259                                         int data_size = t[14] | (t[15] << 8);\r
260                                         \r
261                                         if(sector_num >= 18 && data_size == 512) {\r
262                                                 media_type = MEDIA_TYPE_144;\r
263                                         }\r
264                                         break;\r
265                                 }\r
266                         }\r
267                 }\r
268                 // FIXME: ugly patch for X1turbo ALPHA and ARCUS\r
269                 is_alpha = false;\r
270 #if defined(_X1TURBO) || defined(_X1TURBOZ)\r
271                 if(media_type == MEDIA_TYPE_2D) {\r
272                         uint32 offset = buffer[0x20] | (buffer[0x21] << 8) | (buffer[0x22] << 16) | (buffer[0x23] << 24);\r
273                         uint8 *t = buffer + offset;\r
274                         is_alpha = (strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0);\r
275                 }\r
276 #endif\r
277         }\r
278         delete fi;\r
279 }\r
280 \r
281 void DISK::close()\r
282 {\r
283         // write disk image\r
284         if(inserted) {\r
285                 if(!write_protected && file_size && getcrc32(buffer, file_size) != crc32) {\r
286                         // write image\r
287                         FILEIO* fio = new FILEIO();\r
288                         if(fio->Fopen(dest_path, FILEIO_READ_WRITE_BINARY)) {\r
289                                 fio->Fseek(file_offset, FILEIO_SEEK_SET);\r
290                         } else {\r
291                                 fio->Fopen(dest_path, FILEIO_WRITE_BINARY);\r
292                         }\r
293                         if(fio->IsOpened()) {\r
294                                 if(is_standard_image) {\r
295                                         if(is_fdi_image) {\r
296                                                 fio->Fwrite(fdi_header, 4096, 1);\r
297                                         }\r
298                                         for(int trkside = 0; trkside < 164; trkside++) {\r
299                                                 uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
300                                                 offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
301                                                 offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
302                                                 offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
303                                                 \r
304                                                 if(!offset) {\r
305                                                         break;\r
306                                                 }\r
307                                                 uint8* t = buffer + offset;\r
308                                                 int sector_num = t[4] | (t[5] << 8);\r
309                                                 \r
310                                                 for(int i = 0; i < sector_num; i++) {\r
311                                                         int data_size = t[14] | (t[15] << 8);\r
312                                                         fio->Fwrite(t + 0x10, data_size, 1);\r
313                                                         t += data_size + 0x10;\r
314                                                 }\r
315                                         }\r
316                                 } else {\r
317                                         fio->Fwrite(buffer, file_size, 1);\r
318                                 }\r
319                                 fio->Fclose();\r
320                         }\r
321                         delete fio;\r
322                 }\r
323                 ejected = true;\r
324         }\r
325         inserted = write_protected = false;\r
326         file_size = 0;\r
327         sector_size = sector_num = 0;\r
328         sector = NULL;\r
329 }\r
330 \r
331 bool DISK::get_track(int trk, int side)\r
332 {\r
333         sector_size = sector_num = 0;\r
334         no_skew = true;\r
335         \r
336         // disk not inserted or invalid media type\r
337         if(!(inserted && check_media_type())) {\r
338                 return false;\r
339         }\r
340         \r
341         // search track\r
342         int trkside = trk * 2 + (side & 1);\r
343         if(!(0 <= trkside && trkside < 164)) {\r
344                 return false;\r
345         }\r
346         uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
347         offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
348         offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
349         offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
350         \r
351         if(!offset) {\r
352                 return false;\r
353         }\r
354         \r
355         // track found\r
356         sector = buffer + offset;\r
357         sector_num = sector[4] | (sector[5] << 8);\r
358         \r
359         // create each sector position in track\r
360         int sync_size  = drive_mfm ? 12 : 6;\r
361         int am_size = drive_mfm ? 3 : 0;\r
362         int gap2_size = drive_mfm ? 22 : 11;\r
363         \r
364         data_size_shift = 0;\r
365         too_many_sectors = false;\r
366 retry:\r
367         uint8* t = sector;\r
368         int total = 0, gap3_size;\r
369         \r
370         for(int i = 0; i < sector_num; i++) {\r
371                 int data_size = t[14] | (t[15] << 8);\r
372                 \r
373                 if((data_size >> data_size_shift) < 0x80) {\r
374                         too_many_sectors = true;\r
375                         break;\r
376                 }\r
377                 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size + sync_size + (am_size + 1);\r
378                 total += (data_size >> data_size_shift) + 2;\r
379                 \r
380                 t += data_size + 0x10;\r
381         }\r
382         if(too_many_sectors) {\r
383                 // Too many sectors in this track\r
384                 gap3_size = 32;\r
385                 data_size_shift = 0;\r
386         } else if((gap3_size = (get_track_size() - total) / (sector_num + 2)) < 12) {\r
387                 // ID:N is modified\r
388                 data_size_shift++;\r
389                 goto retry;\r
390         }\r
391         t = sector;\r
392         total = gap3_size * 2;\r
393         \r
394         for(int i = 0; i < sector_num; i++) {\r
395                 int data_size = t[14] | (t[15] << 8);\r
396                 \r
397                 if(too_many_sectors) {\r
398                         total = gap3_size * 2 + (get_track_size() - gap3_size * 2) * i / sector_num;\r
399                 }\r
400                 sync_position[i] = total;\r
401                 total += sync_size + (am_size + 1);\r
402                 id_position[i] = total;\r
403                 total += (4 + 2) + gap2_size + sync_size + (am_size + 1);\r
404                 data_position[i] = total;\r
405                 total += (data_size >> data_size_shift) + 2 + gap3_size;\r
406                 \r
407                 if(t[2] != i + 1) {\r
408                         no_skew = false;\r
409                 }\r
410                 t += data_size + 0x10;\r
411         }\r
412         return true;\r
413 }\r
414 \r
415 bool DISK::make_track(int trk, int side)\r
416 {\r
417         int track_size = get_track_size();\r
418         \r
419         if(!get_track(trk, side)) {\r
420                 // create a dummy track\r
421                 for(int i = 0; i < track_size; i++) {\r
422                         track[i] = rand();\r
423                 }\r
424                 return false;\r
425         }\r
426         \r
427         // make track image\r
428         int sync_size  = drive_mfm ? 12 : 6;\r
429         int am_size = drive_mfm ? 3 : 0;\r
430         int gap2_size = drive_mfm ? 22 : 11;\r
431         uint8 gap_data = drive_mfm ? 0x4e : 0xff;\r
432         \r
433         // preamble\r
434         memset(track, gap_data, track_size);\r
435         \r
436         if(sync_position[0] >= (sync_size + am_size + 1) + (8 + 5)) {\r
437                 int p = (sync_position[0] - (sync_size + am_size + 1)) * 8 / (8 + 5);\r
438                 \r
439                 // sync\r
440                 for(int i = 0; i < sync_size; i++) {\r
441                         track[p++] = 0x00;\r
442                 }\r
443                 // index mark\r
444                 for(int i = 0; i < am_size; i++) {\r
445                         track[p++] = 0xc2;\r
446                 }\r
447                 track[p++] = 0xfc;\r
448         }\r
449         \r
450         // sectors\r
451         uint8 *t = sector;\r
452         \r
453         for(int i = 0; i < sector_num; i++) {\r
454                 int data_size = t[14] | (t[15] << 8);\r
455                 int p = sync_position[i];\r
456                 \r
457                 // sync\r
458                 for(int j = 0; j < sync_size; j++) {\r
459                         if(p < track_size) track[p++] = 0x00;\r
460                 }\r
461                 // am1\r
462                 for(int j = 0; j < am_size; j++) {\r
463                         if(p < track_size) track[p++] = 0xa1;\r
464                 }\r
465                 if(p < track_size) track[p++] = 0xfe;\r
466                 // id\r
467                 if(p < track_size) track[p++] = t[0];\r
468                 if(p < track_size) track[p++] = t[1];\r
469                 if(p < track_size) track[p++] = t[2];\r
470                 if(p < track_size) track[p++] = t[3];\r
471                 uint16 crc = 0;\r
472                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);\r
473                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);\r
474                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);\r
475                 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);\r
476                 if(p < track_size) track[p++] = crc >> 8;\r
477                 if(p < track_size) track[p++] = crc & 0xff;\r
478                 // gap2\r
479                 for(int j = 0; j < gap2_size; j++) {\r
480                         if(p < track_size) track[p++] = gap_data;\r
481                 }\r
482                 // sync\r
483                 for(int j = 0; j < sync_size; j++) {\r
484                         if(p < track_size) track[p++] = 0x00;\r
485                 }\r
486                 // am2\r
487                 for(int j = 0; j < am_size; j++) {\r
488                         if(p < track_size) track[p++] = 0xa1;\r
489                 }\r
490                 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;\r
491                 // data\r
492                 crc = 0;\r
493                 for(int j = 0; j < (data_size >> data_size_shift); j++) {\r
494                         if(p < track_size) track[p++] = t[0x10 + j];\r
495                         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);\r
496                 }\r
497                 if(p < track_size) track[p++] = crc >> 8;\r
498                 if(p < track_size) track[p++] = crc & 0xff;\r
499                 \r
500                 t += data_size + 0x10;\r
501         }\r
502         return true;\r
503 }\r
504 \r
505 bool DISK::get_sector(int trk, int side, int index)\r
506 {\r
507         sector_size = sector_num = 0;\r
508         sector = NULL;\r
509         \r
510         // disk not inserted or invalid media type\r
511         if(!(inserted && check_media_type())) {\r
512                 return false;\r
513         }\r
514         \r
515         // search track\r
516         int trkside = trk * 2 + (side & 1);\r
517         if(!(0 <= trkside && trkside < 164)) {\r
518                 return false;\r
519         }\r
520         uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
521         offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
522         offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
523         offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
524         \r
525         if(!offset) {\r
526                 return false;\r
527         }\r
528         \r
529         // track found\r
530         uint8* t = buffer + offset;\r
531         sector_num = t[4] | (t[5] << 8);\r
532         \r
533         if(index >= sector_num) {\r
534                 return false;\r
535         }\r
536         \r
537         // skip sector\r
538         for(int i = 0; i < index; i++) {\r
539                 t += (t[14] | (t[15] << 8)) + 0x10;\r
540         }\r
541         \r
542         // header info\r
543         id[0] = t[0];\r
544         id[1] = t[1];\r
545         id[2] = t[2];\r
546         id[3] = t[3];\r
547         uint16 crc = 0;\r
548         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);\r
549         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);\r
550         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);\r
551         crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);\r
552         id[4] = crc >> 8;\r
553         id[5] = crc & 0xff;\r
554         density = t[6];\r
555         deleted = t[7];\r
556         status = t[8];\r
557         sector = t + 0x10;\r
558         sector_size = t[14] | (t[15] << 8);\r
559         \r
560         return true;\r
561 }\r
562 \r
563 int DISK::get_rpm()\r
564 {\r
565         if(drive_rpm != 0) {\r
566                 return drive_rpm;\r
567         } else if(inserted) {\r
568                 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;\r
569         } else {\r
570                 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;\r
571         }\r
572 }\r
573 \r
574 int DISK::get_track_size()\r
575 {\r
576         if(inserted) {\r
577                 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;\r
578         } else {\r
579                 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;\r
580         }\r
581 }\r
582 \r
583 double DISK::get_usec_per_bytes(int bytes)\r
584 {\r
585         return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;\r
586 }\r
587 \r
588 bool DISK::check_media_type()\r
589 {\r
590         switch(drive_type) {\r
591         case DRIVE_TYPE_2D:\r
592                 return (media_type == MEDIA_TYPE_2D);\r
593         case DRIVE_TYPE_2DD:\r
594                 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);\r
595         case DRIVE_TYPE_2HD:\r
596                 return (media_type == MEDIA_TYPE_2HD);\r
597         case DRIVE_TYPE_144:\r
598                 return (media_type == MEDIA_TYPE_144);\r
599         case DRIVE_TYPE_UNK:\r
600                 return true; // always okay\r
601         }\r
602         return false;\r
603 }\r
604 \r
605 // teledisk image decoder\r
606 \r
607 /*\r
608         this teledisk image decoder is based on:\r
609         \r
610                 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988\r
611                 LZSS coded by Haruhiko OKUMURA\r
612                 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI\r
613                 Edited and translated to English by Kenji RIKITAKE\r
614                 TDLZHUF.C by WTK\r
615 */\r
616 \r
617 #define COPYBUFFER(src, size) { \\r
618         if(file_size + (size) > DISK_BUFFER_SIZE) { \\r
619                 return false; \\r
620         } \\r
621         memcpy(buffer + file_size, (src), (size)); \\r
622         file_size += (size); \\r
623 }\r
624 \r
625 bool DISK::teledisk_to_d88()\r
626 {\r
627         struct td_hdr_t hdr;\r
628         struct td_cmt_t cmt;\r
629         struct td_trk_t trk;\r
630         struct td_sct_t sct;\r
631         struct d88_hdr_t d88_hdr;\r
632         struct d88_sct_t d88_sct;\r
633         uint8 obuf[512];\r
634         \r
635         // check teledisk header\r
636         fi->Fseek(0, FILEIO_SEEK_SET);\r
637         fi->Fread(&hdr, sizeof(td_hdr_t), 1);\r
638         if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {\r
639                 // decompress to the temporary file\r
640                 FILEIO* fo = new FILEIO();\r
641                 if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {\r
642                         delete fo;\r
643                         return false;\r
644                 }\r
645                 int rd = 1;\r
646                 init_decode();\r
647                 do {\r
648                         if((rd = decode(obuf, 512)) > 0) {\r
649                                 fo->Fwrite(obuf, rd, 1);\r
650                         }\r
651                 }\r
652                 while(rd > 0);\r
653                 fo->Fclose();\r
654                 delete fo;\r
655                 temporary = true;\r
656                 \r
657                 // reopen the temporary file\r
658                 fi->Fclose();\r
659                 if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {\r
660                         return false;\r
661                 }\r
662         }\r
663         if(hdr.flag & 0x80) {\r
664                 // skip comment\r
665                 fi->Fread(&cmt, sizeof(td_cmt_t), 1);\r
666                 fi->Fseek(cmt.len, FILEIO_SEEK_CUR);\r
667         }\r
668         \r
669         // create d88 image\r
670         file_size = 0;\r
671         \r
672         // create d88 header\r
673         memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
674         strcpy(d88_hdr.title, "TELEDISK");\r
675         d88_hdr.protect = 0; // non-protected\r
676         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
677         \r
678         // create tracks\r
679         int trkcnt = 0, trkptr = sizeof(d88_hdr_t);\r
680         fi->Fread(&trk, sizeof(td_trk_t), 1);\r
681         while(trk.nsec != 0xff) {\r
682                 d88_hdr.trkptr[trkcnt++] = trkptr;\r
683                 if(hdr.sides == 1) {\r
684                         d88_hdr.trkptr[trkcnt++] = trkptr;\r
685                 }\r
686                 \r
687                 // read sectors in this track\r
688                 for(int i = 0; i < trk.nsec; i++) {\r
689                         uint8 buf[2048], dst[2048];\r
690                         memset(buf, 0, sizeof(buf));\r
691                         memset(dst, 0, sizeof(dst));\r
692                         \r
693                         // read sector header\r
694                         fi->Fread(&sct, sizeof(td_sct_t), 1);\r
695                         \r
696                         // create d88 sector header\r
697                         memset(&d88_sct, 0, sizeof(d88_sct_t));\r
698                         d88_sct.c = sct.c;\r
699                         d88_sct.h = sct.h;\r
700                         d88_sct.r = sct.r;\r
701                         d88_sct.n = sct.n;\r
702                         d88_sct.nsec = trk.nsec;\r
703                         d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;\r
704                         d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;\r
705                         d88_sct.stat = (sct.ctrl & 2) ? 0x10 : 0; // crc?\r
706                         d88_sct.size = secsize[sct.n & 3];\r
707                         \r
708                         // create sector image\r
709                         if(sct.ctrl != 0x10) {\r
710                                 // read sector source\r
711                                 int len = fi->Fgetc();\r
712                                 len += fi->Fgetc() * 256 - 1;\r
713                                 int flag = fi->Fgetc(), d = 0;\r
714                                 fi->Fread(buf, len, 1);\r
715                                 \r
716                                 // convert\r
717                                 if(flag == 0) {\r
718                                         memcpy(dst, buf, len);\r
719                                 } else if(flag == 1) {\r
720                                         int len2 = buf[0] | (buf[1] << 8);\r
721                                         while(len2--) {\r
722                                                 dst[d++] = buf[2];\r
723                                                 dst[d++] = buf[3];\r
724                                         }\r
725                                 } else if(flag == 2) {\r
726                                         for(int s = 0; s < len;) {\r
727                                                 int type = buf[s++];\r
728                                                 int len2 = buf[s++];\r
729                                                 if(type == 0) {\r
730                                                         while(len2--) {\r
731                                                                 dst[d++] = buf[s++];\r
732                                                         }\r
733                                                 } else if(type < 5) {\r
734                                                         uint8 pat[256];\r
735                                                         int n = 2;\r
736                                                         while(type-- > 1) {\r
737                                                                 n *= 2;\r
738                                                         }\r
739                                                         for(int j = 0; j < n; j++) {\r
740                                                                 pat[j] = buf[s++];\r
741                                                         }\r
742                                                         while(len2--) {\r
743                                                                 for(int j = 0; j < n; j++) {\r
744                                                                         dst[d++] = pat[j];\r
745                                                                 }\r
746                                                         }\r
747                                                 } else {\r
748                                                         break; // unknown type\r
749                                                 }\r
750                                         }\r
751                                 } else {\r
752                                         break; // unknown flag\r
753                                 }\r
754                         } else {\r
755                                 d88_sct.size = 0;\r
756                         }\r
757                         \r
758                         // copy to d88\r
759                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
760                         COPYBUFFER(dst, d88_sct.size);\r
761                         trkptr += sizeof(d88_sct_t) + d88_sct.size;\r
762                 }\r
763                 // read next track\r
764                 fi->Fread(&trk, sizeof(td_trk_t), 1);\r
765         }\r
766         d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;\r
767         d88_hdr.size = trkptr;\r
768         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
769         return true;\r
770 }\r
771 \r
772 int DISK::next_word()\r
773 {\r
774         if(ibufndx >= ibufcnt) {\r
775                 ibufndx = ibufcnt = 0;\r
776                 memset(inbuf, 0, 512);\r
777                 for(int i = 0; i < 512; i++) {\r
778                         int d = fi->Fgetc();\r
779                         if(d == EOF) {\r
780                                 if(i) {\r
781                                         break;\r
782                                 }\r
783                                 return(-1);\r
784                         }\r
785                         inbuf[i] = d;\r
786                         ibufcnt = i + 1;\r
787                 }\r
788         }\r
789         while(getlen <= 8) {\r
790                 getbuf |= inbuf[ibufndx++] << (8 - getlen);\r
791                 getlen += 8;\r
792         }\r
793         return 0;\r
794 }\r
795 \r
796 int DISK::get_bit()\r
797 {\r
798         if(next_word() < 0) {\r
799                 return -1;\r
800         }\r
801         short i = getbuf;\r
802         getbuf <<= 1;\r
803         getlen--;\r
804         return (i < 0) ? 1 : 0;\r
805 }\r
806 \r
807 int DISK::get_byte()\r
808 {\r
809         if(next_word() != 0) {\r
810                 return -1;\r
811         }\r
812         uint16 i = getbuf;\r
813         getbuf <<= 8;\r
814         getlen -= 8;\r
815         i >>= 8;\r
816         return (int)i;\r
817 }\r
818 \r
819 void DISK::start_huff()\r
820 {\r
821         int i, j;\r
822         for(i = 0; i < N_CHAR; i++) {\r
823                 freq[i] = 1;\r
824                 son[i] = i + TABLE_SIZE;\r
825                 prnt[i + TABLE_SIZE] = i;\r
826         }\r
827         i = 0; j = N_CHAR;\r
828         while(j <= ROOT_POSITION) {\r
829                 freq[j] = freq[i] + freq[i + 1];\r
830                 son[j] = i;\r
831                 prnt[i] = prnt[i + 1] = j;\r
832                 i += 2; j++;\r
833         }\r
834         freq[TABLE_SIZE] = 0xffff;\r
835         prnt[ROOT_POSITION] = 0;\r
836 }\r
837 \r
838 void DISK::reconst()\r
839 {\r
840         short i, j = 0, k;\r
841         uint16 f, l;\r
842         for(i = 0; i < TABLE_SIZE; i++) {\r
843                 if(son[i] >= TABLE_SIZE) {\r
844                         freq[j] = (freq[i] + 1) / 2;\r
845                         son[j] = son[i];\r
846                         j++;\r
847                 }\r
848         }\r
849         for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {\r
850                 k = i + 1;\r
851                 f = freq[j] = freq[i] + freq[k];\r
852                 for(k = j - 1; f < freq[k]; k--);\r
853                 k++;\r
854                 l = (j - k) * 2;\r
855                 memmove(&freq[k + 1], &freq[k], l);\r
856                 freq[k] = f;\r
857                 memmove(&son[k + 1], &son[k], l);\r
858                 son[k] = i;\r
859         }\r
860         for(i = 0; i < TABLE_SIZE; i++) {\r
861                 if((k = son[i]) >= TABLE_SIZE) {\r
862                         prnt[k] = i;\r
863                 } else {\r
864                         prnt[k] = prnt[k + 1] = i;\r
865                 }\r
866         }\r
867 }\r
868 \r
869 void DISK::update(int c)\r
870 {\r
871         int i, j, k, l;\r
872         if(freq[ROOT_POSITION] == MAX_FREQ) {\r
873                 reconst();\r
874         }\r
875         c = prnt[c + TABLE_SIZE];\r
876         do {\r
877                 k = ++freq[c];\r
878                 if(k > freq[l = c + 1]) {\r
879                         while(k > freq[++l]);\r
880                         l--;\r
881                         freq[c] = freq[l];\r
882                         freq[l] = k;\r
883                         i = son[c];\r
884                         prnt[i] = l;\r
885                         if(i < TABLE_SIZE) {\r
886                                 prnt[i + 1] = l;\r
887                         }\r
888                         j = son[l];\r
889                         son[l] = i;\r
890                         prnt[j] = c;\r
891                         if(j < TABLE_SIZE) {\r
892                                 prnt[j + 1] = c;\r
893                         }\r
894                         son[c] = j;\r
895                         c = l;\r
896                 }\r
897         }\r
898         while((c = prnt[c]) != 0);\r
899 }\r
900 \r
901 short DISK::decode_char()\r
902 {\r
903         int ret;\r
904         uint16 c = son[ROOT_POSITION];\r
905         while(c < TABLE_SIZE) {\r
906                 if((ret = get_bit()) < 0) {\r
907                         return -1;\r
908                 }\r
909                 c += (unsigned)ret;\r
910                 c = son[c];\r
911         }\r
912         c -= TABLE_SIZE;\r
913         update(c);\r
914         return c;\r
915 }\r
916 \r
917 short DISK::decode_position()\r
918 {\r
919         short bit;\r
920         uint16 i, j, c;\r
921         if((bit = get_byte()) < 0) {\r
922                 return -1;\r
923         }\r
924         i = (uint16)bit;\r
925         c = (uint16)d_code[i] << 6;\r
926         j = d_len[i] - 2;\r
927         while(j--) {\r
928                 if((bit = get_bit()) < 0) {\r
929                          return -1;\r
930                 }\r
931                 i = (i << 1) + bit;\r
932         }\r
933         return (c | i & 0x3f);\r
934 }\r
935 \r
936 void DISK::init_decode()\r
937 {\r
938         ibufcnt= ibufndx = bufcnt = getbuf = 0;\r
939         getlen = 0;\r
940         start_huff();\r
941         for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {\r
942                 text_buf[i] = ' ';\r
943         }\r
944         ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;\r
945 }\r
946 \r
947 int DISK::decode(uint8 *buf, int len)\r
948 {\r
949         short c, pos;\r
950         int  count;\r
951         for(count = 0; count < len;) {\r
952                 if(bufcnt == 0) {\r
953                         if((c = decode_char()) < 0) {\r
954                                 return count;\r
955                         }\r
956                         if(c < 256) {\r
957                                 *(buf++) = (uint8)c;\r
958                                 text_buf[ptr++] = (uint8)c;\r
959                                 ptr &= (STRING_BUFFER_SIZE - 1);\r
960                                 count++;\r
961                         } else {\r
962                                 if((pos = decode_position()) < 0) {\r
963                                         return count;\r
964                                 }\r
965                                 bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);\r
966                                 bufcnt = c - 255 + THRESHOLD;\r
967                                 bufndx = 0;\r
968                         }\r
969                 } else {\r
970                         while(bufndx < bufcnt && count < len) {\r
971                                 c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];\r
972                                 *(buf++) = (uint8)c;\r
973                                 bufndx++;\r
974                                 text_buf[ptr++] = (uint8)c;\r
975                                 ptr &= (STRING_BUFFER_SIZE - 1);\r
976                                 count++;\r
977                         }\r
978                         if(bufndx >= bufcnt) {\r
979                                 bufndx = bufcnt = 0;\r
980                         }\r
981                 }\r
982         }\r
983         return count;\r
984 }\r
985 \r
986 // imagedisk image decoder\r
987 \r
988 bool DISK::imagedisk_to_d88()\r
989 {\r
990         struct imd_trk_t trk;\r
991         struct d88_hdr_t d88_hdr;\r
992         struct d88_sct_t d88_sct;\r
993         \r
994         // skip comment\r
995         fi->Fseek(0, FILEIO_SEEK_SET);\r
996         int tmp;\r
997         while((tmp = fi->Fgetc()) != 0x1a) {\r
998                 if(tmp == EOF) {\r
999                         return false;\r
1000                 }\r
1001         }\r
1002         \r
1003         // create d88 image\r
1004         file_size = 0;\r
1005         \r
1006         // create d88 header\r
1007         memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
1008         strcpy(d88_hdr.title, "IMAGEDISK");\r
1009         d88_hdr.protect = 0; // non-protected\r
1010         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
1011         \r
1012         // create tracks\r
1013         int trkptr = sizeof(d88_hdr_t);\r
1014         int trkcnt = 0, mode;\r
1015         \r
1016         for(int t = 0; t < 164; t++) {\r
1017                 // check end of file\r
1018                 if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {\r
1019                         break;\r
1020                 }\r
1021                 trkcnt = t;\r
1022                 \r
1023                 // check track header\r
1024                 if(t == 0) {\r
1025                         mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps\r
1026                 }\r
1027                 if(!trk.nsec) {\r
1028                         continue;\r
1029                 }\r
1030                 d88_hdr.trkptr[t] = trkptr;\r
1031                 \r
1032                 // setup sector id\r
1033                 uint8 c[64], h[64], r[64];\r
1034                 fi->Fread(r, trk.nsec, 1);\r
1035                 if(trk.head & 0x80) {\r
1036                         fi->Fread(c, trk.nsec, 1);\r
1037                 } else {\r
1038                         memset(c, trk.cyl, sizeof(c));\r
1039                 }\r
1040                 if(trk.head & 0x40) {\r
1041                         fi->Fread(h, trk.nsec, 1);\r
1042                 } else {\r
1043                         memset(h, trk.head & 1, sizeof(h));\r
1044                 }\r
1045                 \r
1046                 // read sectors in this track\r
1047                 for(int i = 0; i < trk.nsec; i++) {\r
1048                         // create d88 sector header\r
1049                         static const uint8 del[] = {0, 0, 0, 0x10, 0x10, 0, 0, 0x10, 0x10};\r
1050                         static const uint8 err[] = {0, 0, 0, 0, 0, 0x10, 0x10, 0x10, 0x10};\r
1051                         int sectype = fi->Fgetc();\r
1052                         if(sectype > 8) {\r
1053                                 return false;\r
1054                         }\r
1055                         memset(&d88_sct, 0, sizeof(d88_sct_t));\r
1056                         d88_sct.c = c[i];\r
1057                         d88_sct.h = h[i];\r
1058                         d88_sct.r = r[i];\r
1059                         d88_sct.n = trk.size;\r
1060                         d88_sct.nsec = trk.nsec;\r
1061                         d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;\r
1062                         d88_sct.del = del[sectype];\r
1063                         d88_sct.stat = err[sectype];\r
1064                         d88_sct.size = secsize[trk.size & 7];\r
1065                         \r
1066                         // create sector image\r
1067                         uint8 dst[8192];\r
1068                         if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {\r
1069                                 // uncompressed\r
1070                                 fi->Fread(dst, d88_sct.size, 1);\r
1071                         } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {\r
1072                                 // compressed\r
1073                                 int tmp = fi->Fgetc();\r
1074                                 memset(dst, tmp, d88_sct.size);\r
1075                         } else {\r
1076                                 d88_sct.size = 0;\r
1077                         }\r
1078                         \r
1079                         // copy to d88\r
1080                         COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
1081                         COPYBUFFER(dst, d88_sct.size);\r
1082                         trkptr += sizeof(d88_sct_t) + d88_sct.size;\r
1083                 }\r
1084         }\r
1085         d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;\r
1086         d88_hdr.size = trkptr;\r
1087         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
1088         return true;\r
1089 }\r
1090 \r
1091 // cpdread image decoder (from MESS formats/dsk_dsk.c)\r
1092 \r
1093 bool DISK::cpdread_to_d88(int extended)\r
1094 {\r
1095         struct d88_hdr_t d88_hdr;\r
1096         struct d88_sct_t d88_sct;\r
1097         int total = 0;\r
1098         \r
1099         // get cylinder number and side number\r
1100         memcpy(tmp_buffer, buffer, file_size);\r
1101         int ncyl = tmp_buffer[0x30];\r
1102         int nside = tmp_buffer[0x31];\r
1103         \r
1104         // create d88 image\r
1105         file_size = 0;\r
1106         \r
1107         // create d88 header\r
1108         memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
1109         strcpy(d88_hdr.title, "CPDRead");\r
1110         d88_hdr.protect = 0; // non-protected\r
1111         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
1112         \r
1113         // create tracks\r
1114         int trkofs = 0x100, trkofs_ptr = 0x34;\r
1115         int trkptr = sizeof(d88_hdr_t);\r
1116         \r
1117         for(int c = 0; c < ncyl; c++) {\r
1118                 for(int h = 0; h < nside; h++) {\r
1119                         // read sectors in this track\r
1120                         uint8 *track_info = tmp_buffer + trkofs;\r
1121                         int cyl = track_info[0x10];\r
1122                         int side = track_info[0x11];\r
1123                         int nsec = track_info[0x15];\r
1124                         int size = 1 << (track_info[0x14] + 7); // standard\r
1125                         int sctofs = trkofs + 0x100;\r
1126                         \r
1127                         if(nside == 1) {\r
1128                                 // double side\r
1129                                 d88_hdr.trkptr[2 * cyl] = d88_hdr.trkptr[2 * cyl + 1] = trkptr;\r
1130                         } else {\r
1131                                 d88_hdr.trkptr[2 * cyl + side] = trkptr;\r
1132                         }\r
1133                         for(int s = 0; s < nsec; s++) {\r
1134                                 // get sector size\r
1135                                 uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;\r
1136                                 if(extended) {\r
1137                                         size = sector_info[6] + sector_info[7] * 256;\r
1138                                 }\r
1139                                 \r
1140                                 // create d88 sector header\r
1141                                 memset(&d88_sct, 0, sizeof(d88_sct_t));\r
1142                                 d88_sct.c = sector_info[0];\r
1143                                 d88_sct.h = sector_info[1];\r
1144                                 d88_sct.r = sector_info[2];\r
1145                                 d88_sct.n = sector_info[3];\r
1146                                 d88_sct.nsec = nsec;\r
1147                                 d88_sct.dens = 0;\r
1148                                 d88_sct.del = (sector_info[5] & 0x40) ? 0x10 : 0;\r
1149                                 d88_sct.stat = 0;\r
1150                                 d88_sct.size = size;\r
1151                                 \r
1152                                 // copy to d88\r
1153                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
1154                                 COPYBUFFER(tmp_buffer + sctofs, size);\r
1155                                 trkptr += sizeof(d88_sct_t) + size;\r
1156                                 sctofs += size;\r
1157                                 total += size;\r
1158                         }\r
1159                         \r
1160                         if(extended) {\r
1161                                 trkofs += tmp_buffer[trkofs_ptr++] * 256;\r
1162                         } else {\r
1163                                 trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;\r
1164                         }\r
1165                 }\r
1166         }\r
1167         d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;\r
1168         d88_hdr.size = trkptr;\r
1169         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
1170         return true;\r
1171 }\r
1172 \r
1173 // standard image decoder\r
1174 \r
1175 bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size)\r
1176 {\r
1177         struct d88_hdr_t d88_hdr;\r
1178         struct d88_sct_t d88_sct;\r
1179         int n = 0, t = 0;\r
1180         \r
1181         file_size = 0;\r
1182         \r
1183         // create d88 header\r
1184         memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
1185         strcpy(d88_hdr.title, "STANDARD");\r
1186         d88_hdr.protect = 0; // non-protected\r
1187         d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;\r
1188         media_type = type;\r
1189         COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
1190         \r
1191         // sector length\r
1192         for(int i = 0; i < 8; i++) {\r
1193                 if(size == (128 << i)) {\r
1194                         n = i;\r
1195                         break;\r
1196                 }\r
1197         }\r
1198         \r
1199         // create tracks\r
1200         int trkptr = sizeof(d88_hdr_t);\r
1201         for(int c = 0; c < ncyl; c++) {\r
1202                 for(int h = 0; h < nside; h++) {\r
1203                         d88_hdr.trkptr[t++] = trkptr;\r
1204                         if(nside == 1) {\r
1205                                 // double side\r
1206                                 d88_hdr.trkptr[t++] = trkptr;\r
1207                         }\r
1208                         \r
1209                         // read sectors in this track\r
1210                         for(int s = 0; s < nsec; s++) {\r
1211                                 // create d88 sector header\r
1212                                 memset(&d88_sct, 0, sizeof(d88_sct_t));\r
1213                                 d88_sct.c = c;\r
1214                                 d88_sct.h = h;\r
1215                                 d88_sct.r = s + 1;\r
1216                                 d88_sct.n = n;\r
1217                                 d88_sct.nsec = nsec;\r
1218                                 d88_sct.dens = 0;\r
1219                                 d88_sct.del = 0;\r
1220                                 d88_sct.stat = 0;\r
1221                                 d88_sct.size = size;\r
1222                                 \r
1223                                 // create sector image\r
1224                                 uint8 dst[16384];\r
1225                                 memset(dst, 0xe5, sizeof(dst));\r
1226                                 fi->Fread(dst, size, 1);\r
1227                                 \r
1228                                 // copy to d88\r
1229                                 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
1230                                 COPYBUFFER(dst, size);\r
1231                                 trkptr += sizeof(d88_sct_t) + size;\r
1232                         }\r
1233                 }\r
1234         }\r
1235         d88_hdr.size = trkptr;\r
1236         memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
1237         return true;\r
1238 }\r
1239 \r
1240 #define STATE_VERSION   1\r
1241 \r
1242 void DISK::save_state(FILEIO* state_fio)\r
1243 {\r
1244         state_fio->FputUint32(STATE_VERSION);\r
1245         \r
1246         state_fio->Fwrite(buffer, sizeof(buffer), 1);\r
1247         state_fio->Fwrite(orig_path, sizeof(orig_path), 1);\r
1248         state_fio->Fwrite(dest_path, sizeof(dest_path), 1);\r
1249         state_fio->FputInt32(file_size);\r
1250         state_fio->FputInt32(file_offset);\r
1251         state_fio->FputUint32(crc32);\r
1252         state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);\r
1253         state_fio->FputBool(inserted);\r
1254         state_fio->FputBool(ejected);\r
1255         state_fio->FputBool(write_protected);\r
1256         state_fio->FputBool(changed);\r
1257         state_fio->FputUint8(media_type);\r
1258         state_fio->FputBool(is_standard_image);\r
1259         state_fio->FputBool(is_fdi_image);\r
1260         state_fio->FputBool(is_alpha);\r
1261         state_fio->Fwrite(track, sizeof(track), 1);\r
1262         state_fio->FputInt32(sector_num);\r
1263         state_fio->FputInt32(data_size_shift);\r
1264         state_fio->FputBool(too_many_sectors);\r
1265         state_fio->FputBool(no_skew);\r
1266         state_fio->Fwrite(sync_position, sizeof(sync_position), 1);\r
1267         state_fio->Fwrite(id_position, sizeof(id_position), 1);\r
1268         state_fio->Fwrite(data_position, sizeof(data_position), 1);\r
1269         state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);\r
1270         state_fio->FputInt32(sector_size);\r
1271         state_fio->Fwrite(id, sizeof(id), 1);\r
1272         state_fio->FputUint8(density);\r
1273         state_fio->FputUint8(deleted);\r
1274         state_fio->FputUint8(status);\r
1275         state_fio->FputUint8(drive_type);\r
1276         state_fio->FputInt32(drive_rpm);\r
1277         state_fio->FputBool(drive_mfm);\r
1278 }\r
1279 \r
1280 bool DISK::load_state(FILEIO* state_fio)\r
1281 {\r
1282         if(state_fio->FgetUint32() != STATE_VERSION) {\r
1283                 return false;\r
1284         }\r
1285         state_fio->Fread(buffer, sizeof(buffer), 1);\r
1286         state_fio->Fread(orig_path, sizeof(orig_path), 1);\r
1287         state_fio->Fread(dest_path, sizeof(dest_path), 1);\r
1288         file_size = state_fio->FgetInt32();\r
1289         file_offset = state_fio->FgetInt32();\r
1290         crc32 = state_fio->FgetUint32();\r
1291         state_fio->Fread(fdi_header, sizeof(fdi_header), 1);\r
1292         inserted = state_fio->FgetBool();\r
1293         ejected = state_fio->FgetBool();\r
1294         write_protected = state_fio->FgetBool();\r
1295         changed = state_fio->FgetBool();\r
1296         media_type = state_fio->FgetUint8();\r
1297         is_standard_image = state_fio->FgetBool();\r
1298         is_fdi_image = state_fio->FgetBool();\r
1299         is_alpha = state_fio->FgetBool();\r
1300         state_fio->Fread(track, sizeof(track), 1);\r
1301         sector_num = state_fio->FgetInt32();\r
1302         data_size_shift = state_fio->FgetInt32();\r
1303         too_many_sectors = state_fio->FgetBool();\r
1304         no_skew = state_fio->FgetBool();\r
1305         state_fio->Fread(sync_position, sizeof(sync_position), 1);\r
1306         state_fio->Fread(id_position, sizeof(id_position), 1);\r
1307         state_fio->Fread(data_position, sizeof(data_position), 1);\r
1308         int offset = state_fio->FgetInt32();\r
1309         sector = (offset != -1) ? buffer + offset : NULL;\r
1310         sector_size = state_fio->FgetInt32();\r
1311         state_fio->Fread(id, sizeof(id), 1);\r
1312         density = state_fio->FgetUint8();\r
1313         deleted = state_fio->FgetUint8();\r
1314         status = state_fio->FgetUint8();\r
1315         drive_type = state_fio->FgetUint8();\r
1316         drive_rpm = state_fio->FgetInt32();\r
1317         drive_mfm = state_fio->FgetBool();\r
1318         return true;\r
1319 }\r
1320 \r