OSDN Git Service

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