OSDN Git Service

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