OSDN Git Service

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