2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../config.h"
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
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
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
70 static const int secsize[8] = {
71 128, 256, 512, 1024, 2048, 4096, 8192, 16384
74 static uint8 tmp_buffer[DISK_BUFFER_SIZE];
78 int ncyl, nside, nsec, size;
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
87 { MEDIA_TYPE_2D , 40, 2, 16, 256 }, // 2D 320KB
88 { MEDIA_TYPE_2D, 40, 2, 9, 512 }, // 2D 360KB
90 #if defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
91 { MEDIA_TYPE_2DD, 80, 2, 16, 256 }, // 2DD 640KB (MZ-2500)
93 { MEDIA_TYPE_2DD, 80, 2, 8, 512 }, // 2DD 640KB
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
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
106 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
108 void DISK::open(_TCHAR path[], int bank)
110 // check current disk image
112 if(_tcsicmp(orig_path, path) == 0 && file_bank == bank) {
117 memset(buffer, 0, sizeof(buffer));
118 media_type = MEDIA_TYPE_UNK;
119 is_solid_image = is_fdi_image = is_1dd_image = false;
120 trim_required = false;
124 if(fi->Fopen(path, FILEIO_READ_BINARY)) {
125 bool converted = false;
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);
132 write_protected = false; //FILEIO::IsFileProtected(path);
134 // is this d88 format ?
135 if(check_file_extension(path, _T(".d88")) || check_file_extension(path, _T(".d77")) || check_file_extension(path, _T(".1dd"))) {
137 for(int i = 0; i < bank; i++) {
138 fi->Fseek(offset + 0x1c, SEEK_SET);
139 offset += fi->FgetUint32_LE();
141 fi->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
142 file_size.d = fi->FgetUint32_LE();
143 fi->Fseek(offset, FILEIO_SEEK_SET);
144 fi->Fread(buffer, file_size.d, 1);
146 inserted = changed = true;
147 is_1dd_image = check_file_extension(path, _T(".1dd"));
148 // trim_required = true;
150 // fix sector number from big endian to little endian
151 for(int trkside = 0; trkside < 164; trkside++) {
153 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
155 if(!IS_VALID_TRACK(offset.d)) {
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);
163 sector_num.read_2bytes_be_from(t + 4);
164 sector_num.write_2bytes_le_to(t + 4);
166 for(int i = 0; i < sector_num.sd; i++) {
168 sector_num.write_2bytes_le_to(t + 4);
170 data_size.read_2bytes_le_from(t + 14);
171 t += data_size.sd + 0x10;
177 fi->Fseek(0, FILEIO_SEEK_END);
178 file_size.d = fi->Ftell();
179 fi->Fseek(0, FILEIO_SEEK_SET);
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(solid_to_d88(MEDIA_TYPE_2D, 40, 2, 16, 256)) {
186 inserted = changed = is_solid_image = true;
189 fi->Fseek(0, FILEIO_SEEK_SET);
193 // check image file format
194 for(int i = 0;; i++) {
195 const fd_format_t *p = &fd_formats[i];
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) {
204 fi->Fread(fdi_header, 4096, 1);
206 if(solid_to_d88(p->type, p->ncyl, p->nside, p->nsec, p->size)) {
207 inserted = changed = is_solid_image = true;
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);
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;
221 _stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), path);
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);
239 // failed to convert the disk image
247 FILEIO::RemoveFile(temp_path);
250 if(buffer[0x1a] != 0) {
252 write_protected = true;
257 FILEIO* fio = new FILEIO();
258 if(fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
259 fio->Fwrite(buffer, file_size.d, 1);
265 crc32 = getcrc32(buffer, file_size.d);
267 if(media_type == MEDIA_TYPE_UNK) {
269 media_type = MEDIA_TYPE_2DD;
270 } else if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
271 for(int trkside = 0; trkside < 164; trkside++) {
273 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
275 if(!IS_VALID_TRACK(offset.d)) {
279 uint8 *t = buffer + offset.d;
280 pair sector_num, data_size;
281 sector_num.read_2bytes_le_from(t + 4);
282 data_size.read_2bytes_le_from(t + 14);
284 if(sector_num.sd >= 18 && data_size.sd == 512) {
285 media_type = MEDIA_TYPE_144;
292 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
293 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha
294 if(media_type == MEDIA_TYPE_2D) {
296 pair offset, sector_num, data_size;
297 offset.read_4bytes_le_from(buffer + 0x20);
298 if(IS_VALID_TRACK(offset.d)) {
299 // check the sector (c,h,r,n)=(0,0,7,1)
300 uint8* t = buffer + offset.d;
301 sector_num.read_2bytes_le_from(t + 4);
302 for(int i = 0; i < sector_num.sd; i++) {
303 data_size.read_2bytes_le_from(t + 14);
304 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
305 static const uint8 gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
306 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
307 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
311 t += data_size.sd + 0x10;
313 if(is_special_disk == 0) {
314 t = buffer + offset.d;
315 sector_num.read_2bytes_le_from(t + 4);
317 for(int i = 0; i < sector_num.sd; i++) {
318 data_size.read_2bytes_le_from(t + 14);
319 // FIXME : Check DEATH FORCE
320 if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 0x02) {
321 static const uint8 deathforce[] ={
322 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
323 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
324 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
325 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
326 0x00, 0x00}; //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
327 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
328 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
332 t += data_size.sd + 0x10;
335 if(is_special_disk == 0) {
336 t = buffer + offset.d;
337 sector_num.read_2bytes_le_from(t + 4);
339 for(int i = 0; i < sector_num.sd; i++) {
340 data_size.read_2bytes_le_from(t + 14);
341 // FIXME : Check Psy-O-Blade (Program)
342 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x01 && t[3] == 0x01) {
343 static const uint8 psyoblade_ipl1[] ={
344 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
345 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
346 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
347 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
348 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
349 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
351 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc" + $B6 + $FD + $05
352 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
353 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
354 //printf("Disk: PSY-O-BLADE\n");
358 t += data_size.sd + 0x10;
361 if(is_special_disk == 0) {
362 t = buffer + offset.d;
363 sector_num.read_2bytes_le_from(t + 4);
365 for(int i = 0; i < sector_num.sd; i++) {
366 data_size.read_2bytes_le_from(t + 14);
367 // FIXME : Check Psy-O-Blade (Program)
368 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 0x01 && t[3] == 0x01) {
370 static const uint8 psyoblade_disk_1[] ={
371 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
372 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
373 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
374 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
376 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
377 static const uint8 psyoblade_disk_2[] ={
378 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
379 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
380 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20};
381 if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
382 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
383 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
384 //printf("Disk: PSY-O-BLADE\n");
389 t += data_size.sd + 0x10;
394 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
395 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
396 if(media_type == MEDIA_TYPE_2D) {
399 offset.read_4bytes_le_from(buffer + 0x20);
400 if(IS_VALID_TRACK(offset.d)) {
401 // check first sector
402 static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
403 uint8 *t = buffer + offset.d;
404 #if defined(_X1TURBO) || defined(_X1TURBOZ)
405 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
406 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
409 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
410 is_special_disk = SPECIAL_DISK_X1_BATTEN;
425 trim_required = false;
427 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
429 if(/*!write_protected &&*/ file_size.d && getcrc32(buffer, file_size.d) != crc32) {
431 FILEIO* fio = new FILEIO();
432 int pre_size = 0, post_size = 0;
433 uint8 *pre_buffer = NULL, *post_buffer = NULL;
435 // is this d88 format ?
436 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
437 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
438 fio->Fseek(0, FILEIO_SEEK_END);
439 uint32 total_size = fio->Ftell(), offset = 0;
440 for(int i = 0; i < file_bank; i++) {
441 fio->Fseek(offset + 0x1c, SEEK_SET);
442 offset += fio->FgetUint32_LE();
444 if((pre_size = offset) > 0) {
445 pre_buffer = (uint8 *)malloc(pre_size);
446 fio->Fseek(0, FILEIO_SEEK_SET);
447 fio->Fread(pre_buffer, pre_size, 1);
449 fio->Fseek(offset + 0x1c, SEEK_SET);
450 offset += fio->FgetUint32_LE();
451 if((post_size = total_size - offset) > 0) {
452 post_buffer = (uint8 *)malloc(post_size);
453 fio->Fseek(offset, FILEIO_SEEK_SET);
454 fio->Fread(post_buffer, post_size, 1);
459 if((FILEIO::IsFileExists(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
460 _TCHAR tmp_path[_MAX_PATH];
461 _stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
462 fio->Fopen(emu->bios_path(tmp_path), FILEIO_WRITE_BINARY);
464 if(fio->IsOpened()) {
466 fio->Fwrite(pre_buffer, pre_size, 1);
470 fio->Fwrite(fdi_header, 4096, 1);
472 for(int trkside = 0; trkside < 164; trkside++) {
474 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
476 if(!IS_VALID_TRACK(offset.d)) {
479 uint8* t = buffer + offset.d;
480 pair sector_num, data_size;
481 sector_num.read_2bytes_le_from(t + 4);
483 for(int i = 0; i < sector_num.sd; i++) {
484 data_size.read_2bytes_le_from(t + 14);
485 fio->Fwrite(t + 0x10, data_size.sd, 1);
486 t += data_size.sd + 0x10;
490 fio->Fwrite(buffer, file_size.d, 1);
493 fio->Fwrite(post_buffer, post_size, 1);
507 inserted = write_protected = false;
509 sector_size.sd = sector_num.sd = 0;
513 bool DISK::get_track(int trk, int side)
515 sector_size.sd = sector_num.sd = 0;
516 invalid_format = false;
519 // disk not inserted or invalid media type
520 if(!(inserted && check_media_type())) {
524 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
525 if(!(0 <= trkside && trkside < 164)) {
532 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
534 if(!IS_VALID_TRACK(offset.d)) {
539 sector = buffer + offset.d;
540 sector_num.read_2bytes_le_from(sector + 4);
542 data_size.read_2bytes_le_from(sector + 14);
544 // create each sector position in track
545 int sync_size = drive_mfm ? 12 : 6;
546 int am_size = drive_mfm ? 3 : 0;
547 int gap0_size = drive_mfm ? 80 : 40;
548 int gap1_size = drive_mfm ? 50 : 26;
549 int gap2_size = drive_mfm ? 22 : 11;
550 int gap3_size = 0, gap4_size;
552 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
554 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
555 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
556 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
558 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
559 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
560 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
564 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
565 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
566 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
568 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
569 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
570 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
575 int total = sync_size + (am_size + 1);
577 for(int i = 0; i < sector_num.sd; i++) {
578 data_size.read_2bytes_le_from(t + 14);
579 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
580 if(data_size.sd > 0) {
581 total += sync_size + (am_size + 1);
582 total += data_size.sd + 2;
587 t += data_size.sd + 0x10;
590 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (sector_num.sd + 1);
592 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
594 if(gap3_size < 8 || gap4_size < 8) {
595 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + sector_num.sd + 1);
596 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
598 if(gap3_size < 8 || gap4_size < 8) {
599 gap0_size = gap1_size = gap3_size = gap4_size = 32;
600 invalid_format = true;
602 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
605 total = preamble_size;
606 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
608 for(int i = 0; i < sector_num.sd; i++) {
609 data_size.read_2bytes_le_from(t + 14);
611 total = preamble_size + (get_track_size() - preamble_size - gap4_size) * i / sector_num.sd;
613 sync_position[i] = total;
614 total += sync_size + (am_size + 1);
615 id_position[i] = total;
616 total += (4 + 2) + gap2_size;
617 if(data_size.sd > 0) {
618 total += sync_size + (am_size + 1);
619 data_position[i] = total;
620 total += data_size.sd + 2;
622 data_position[i] = total; // FIXME
625 t += data_size.sd + 0x10;
630 bool DISK::make_track(int trk, int side)
632 int track_size = get_track_size();
634 if(!get_track(trk, side)) {
635 // create a dummy track
636 for(int i = 0; i < track_size; i++) {
643 int sync_size = drive_mfm ? 12 : 6;
644 int am_size = drive_mfm ? 3 : 0;
645 int gap2_size = drive_mfm ? 22 : 11;
646 uint8 gap_data = drive_mfm ? 0x4e : 0xff;
649 memset(track, gap_data, track_size);
650 int q = sync_position[array_length(sync_position) - 1];
653 for(int i = 0; i < sync_size; i++) {
657 for(int i = 0; i < am_size; i++) {
665 for(int i = 0; i < sector_num.sd; i++) {
667 data_size.read_2bytes_le_from(t + 14);
668 int p = sync_position[i];
671 for(int j = 0; j < sync_size; j++) {
672 if(p < track_size) track[p++] = 0x00;
675 for(int j = 0; j < am_size; j++) {
676 if(p < track_size) track[p++] = 0xa1;
678 if(p < track_size) track[p++] = 0xfe;
680 if(p < track_size) track[p++] = t[0];
681 if(p < track_size) track[p++] = t[1];
682 if(p < track_size) track[p++] = t[2];
683 if(p < track_size) track[p++] = t[3];
685 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
686 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
687 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
688 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
689 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
690 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
692 for(int j = 0; j < gap2_size; j++) {
693 if(p < track_size) track[p++] = gap_data;
696 if(data_size.sd > 0) {
698 for(int j = 0; j < sync_size; j++) {
699 if(p < track_size) track[p++] = 0x00;
702 for(int j = 0; j < am_size; j++) {
703 if(p < track_size) track[p++] = 0xa1;
705 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
708 for(int j = 0; j < data_size.sd; j++) {
709 if(p < track_size) track[p++] = t[0x10 + j];
710 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
712 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
713 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
715 t += data_size.sd + 0x10;
720 bool DISK::get_sector(int trk, int side, int index)
722 sector_size.sd = sector_num.sd = 0;
725 // disk not inserted or invalid media type
726 if(!(inserted && check_media_type())) {
731 if(trk == -1 && side == -1) {
735 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
736 if(!(0 <= trkside && trkside < 164)) {
740 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
742 if(!IS_VALID_TRACK(offset.d)) {
747 uint8* t = buffer + offset.d;
748 sector_num.read_2bytes_le_from(t + 4);
750 if(index >= sector_num.sd) {
755 for(int i = 0; i < index; i++) {
757 data_size.read_2bytes_le_from(t + 14);
758 t += data_size.sd + 0x10;
764 void DISK::set_sector_info(uint8 *t)
772 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
773 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
774 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
775 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
776 id[4] = (crc >> 8) & 0xff;
777 id[5] = (crc >> 0) & 0xff;
778 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
779 // t[6]: 0x00 = double-density, 0x40 = single-density
780 // t[7]: 0x00 = normal, 0x10 = deleted mark
781 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
783 deleted = (t[7] != 0);
785 // if(ignore_crc()) {
786 // crc_error = false;
788 // crc_error = (((t[8] & 0xf0) != 0x00) && ((t[8] & 0xf0) != 0x10));
789 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
790 data_crc_error = ((t[8] & 0xf0) == 0xb0);
793 sector_size.read_2bytes_le_from(t + 14);
796 void DISK::set_deleted(bool value)
799 uint8 *t = sector - 0x10;
800 t[7] = value ? 0x10 : 0;
801 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
802 t[8] = (t[8] & 0x0f) | t[7];
808 void DISK::set_data_crc_error(bool value)
811 uint8 *t = sector - 0x10;
812 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
814 data_crc_error = value;
817 void DISK::set_data_mark_missing()
820 uint8 *t = sector - 0x10;
821 //t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]); // FIXME: always data crc error ?
822 t[8] = (t[8] & 0x0f) | 0xf0;
826 //addr_crc_error = value;
827 data_crc_error = false;
830 bool DISK::format_track(int trk, int side)
832 // disk not inserted or invalid media type
833 if(!(inserted && check_media_type())) {
838 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
839 if(!(0 <= trkside && trkside < 164)) {
843 // create new empty track
846 trim_required = false;
848 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
850 offset.d = DISK_BUFFER_SIZE;
851 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
853 trim_required = true;
858 void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool data_crc_error, uint8 fill_data, int length)
860 uint8* t = buffer + DISK_BUFFER_SIZE;
863 for(int i = 0; i < (sector_num.sd - 1); i++) {
864 t[4] = sector_num.b.l;
865 t[5] = sector_num.b.h;
867 data_size.read_2bytes_le_from(t + 14);
868 t += data_size.sd + 0x10;
874 t[4] = sector_num.b.l;
875 t[5] = sector_num.b.h;
876 t[6] = drive_mfm ? 0 : 0x40;
877 t[7] = deleted ? 0x10 : 0;
878 t[8] = data_crc_error ? 0xb0 : t[7];
879 t[14] = (length >> 0) & 0xff;
880 t[15] = (length >> 8) & 0xff;
881 memset(t + 16, fill_data, length);
886 void DISK::sync_buffer()
890 trim_required = false;
894 void DISK::trim_buffer()
896 int max_tracks = 164;
897 uint32 dest_offset = 0x2b0;
900 memset(tmp_buffer, 0, sizeof(tmp_buffer));
901 memcpy(tmp_buffer, buffer, 0x20);
904 for(int trkside = 0; trkside < 164; trkside++) {
906 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
907 if(src_trk_offset.d != 0) {
909 if(src_trk_offset.d < 0x2b0) {
910 max_tracks = (src_trk_offset.d - 0x20) >> 2;
913 if(src_trk_offset.d != 0x2b0) {
914 max_tracks = (src_trk_offset.d - 0x20) >> 2;
915 if(max_tracks > 164) {
916 dest_offset = 0x20 + max_tracks * 4);
925 for(int trkside = 0; trkside < max_tracks; trkside++) {
927 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
929 pair dest_trk_offset;
930 dest_trk_offset.d = 0;
932 if(IS_VALID_TRACK(src_trk_offset.d)) {
933 uint8* t = buffer + src_trk_offset.d;
934 pair sector_num, data_size;
935 sector_num.read_2bytes_le_from(t + 4);
936 if(sector_num.sd != 0) {
937 dest_trk_offset.d = dest_offset;
938 for(int i = 0; i < sector_num.sd; i++) {
939 data_size.read_2bytes_le_from(t + 14);
940 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
941 dest_offset += data_size.sd + 0x10;
942 t += data_size.sd + 0x10;
946 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
950 file_size.d = dest_offset;
951 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
953 memset(buffer, 0, sizeof(buffer));
954 memcpy(buffer, tmp_buffer, (file_size.d > sizeof(buffer)) ? sizeof(buffer) : file_size.d);
961 } else if(inserted) {
962 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
964 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
968 int DISK::get_track_size()
971 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
972 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3100;
974 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
976 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
977 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3100;
979 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
983 double DISK::get_usec_per_track()
985 return 1000000.0 / (get_rpm() / 60.0);
988 double DISK::get_usec_per_bytes(int bytes)
990 #if defined(_FM77AV_VARIANTS)
991 if(is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) {
992 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0) * 2.0) * bytes;
995 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
998 int DISK::get_bytes_per_usec(double usec)
1000 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1003 bool DISK::check_media_type()
1005 switch(drive_type) {
1007 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1008 defined(_FM77AV20) || defined(_FM77AV20EX) || defined(_FM77AV20SX)
1009 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1011 return (media_type == MEDIA_TYPE_2D);
1013 case DRIVE_TYPE_2DD:
1014 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1015 case DRIVE_TYPE_2HD:
1016 return (media_type == MEDIA_TYPE_2HD);
1017 case DRIVE_TYPE_144:
1018 return (media_type == MEDIA_TYPE_144);
1019 case DRIVE_TYPE_UNK:
1020 return true; // always okay
1027 #define COPYBUFFER(src, size) { \
1028 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1031 memcpy(buffer + file_size.d, (src), (size)); \
1032 file_size.d += (size); \
1047 uint8 dens, del, stat;
1052 // teledisk image decoder
1055 this teledisk image decoder is based on:
1057 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1058 LZSS coded by Haruhiko OKUMURA
1059 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1060 Edited and translated to English by Kenji RIKITAKE
1084 uint8 nsec, trk, head;
1093 bool DISK::teledisk_to_d88()
1103 // check teledisk header
1104 fi->Fseek(0, FILEIO_SEEK_SET);
1105 fi->Fread(&hdr, sizeof(td_hdr_t), 1);
1106 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1107 // decompress to the temporary file
1108 FILEIO* fo = new FILEIO();
1109 if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {
1116 if((rd = decode(obuf, 512)) > 0) {
1117 fo->Fwrite(obuf, rd, 1);
1125 // reopen the temporary file
1127 if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {
1131 if(hdr.flag & 0x80) {
1133 fi->Fread(&cmt, sizeof(td_cmt_t), 1);
1134 fi->Fseek(cmt.len, FILEIO_SEEK_CUR);
1140 // create d88 header
1141 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1142 _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1143 d88_hdr.protect = 0; // non-protected
1144 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1147 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1148 fi->Fread(&trk, sizeof(td_trk_t), 1);
1149 while(trk.nsec != 0xff) {
1150 d88_hdr.trkptr[trkcnt++] = trkptr;
1151 if(hdr.sides == 1) {
1155 // read sectors in this track
1156 for(int i = 0; i < trk.nsec; i++) {
1157 uint8 buf[2048], dst[2048];
1158 memset(buf, 0, sizeof(buf));
1159 memset(dst, 0, sizeof(dst));
1161 // read sector header
1162 fi->Fread(&sct, sizeof(td_sct_t), 1);
1164 // create d88 sector header
1165 memset(&d88_sct, 0, sizeof(d88_sct_t));
1170 d88_sct.nsec = trk.nsec;
1171 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1172 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1173 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1174 d88_sct.size = secsize[sct.n & 3];
1176 // create sector image
1177 if(sct.ctrl & 0x30) {
1178 d88_sct.stat = 0xf0; // data mark missing
1181 // read sector source
1182 int len = fi->Fgetc();
1183 len += fi->Fgetc() * 256 - 1;
1184 int flag = fi->Fgetc(), d = 0;
1185 fi->Fread(buf, len, 1);
1189 memcpy(dst, buf, len);
1190 } else if(flag == 1) {
1192 len2.read_2bytes_le_from(buf);
1197 } else if(flag == 2) {
1198 for(int s = 0; s < len;) {
1199 int type = buf[s++];
1200 int len2 = buf[s++];
1203 dst[d++] = buf[s++];
1205 } else if(type < 5) {
1211 for(int j = 0; j < n; j++) {
1215 for(int j = 0; j < n; j++) {
1220 break; // unknown type
1224 break; // unknown flag
1229 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1230 COPYBUFFER(dst, d88_sct.size);
1231 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1234 fi->Fread(&trk, sizeof(td_trk_t), 1);
1236 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 45) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1237 d88_hdr.size = trkptr;
1238 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1242 int DISK::next_word()
1244 if(ibufndx >= ibufcnt) {
1245 ibufndx = ibufcnt = 0;
1246 memset(inbuf, 0, 512);
1247 for(int i = 0; i < 512; i++) {
1248 int d = fi->Fgetc();
1259 while(getlen <= 8) {
1260 getbuf |= inbuf[ibufndx++] << (8 - getlen);
1268 if(next_word() < 0) {
1274 return (i < 0) ? 1 : 0;
1277 int DISK::get_byte()
1279 if(next_word() != 0) {
1289 void DISK::start_huff()
1292 for(i = 0; i < N_CHAR; i++) {
1294 son[i] = i + TABLE_SIZE;
1295 prnt[i + TABLE_SIZE] = i;
1298 while(j <= ROOT_POSITION) {
1299 freq[j] = freq[i] + freq[i + 1];
1301 prnt[i] = prnt[i + 1] = j;
1304 freq[TABLE_SIZE] = 0xffff;
1305 prnt[ROOT_POSITION] = 0;
1308 void DISK::reconst()
1312 for(i = 0; i < TABLE_SIZE; i++) {
1313 if(son[i] >= TABLE_SIZE) {
1314 freq[j] = (freq[i] + 1) / 2;
1319 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1321 f = freq[j] = freq[i] + freq[k];
1322 for(k = j - 1; f < freq[k]; k--);
1325 memmove(&freq[k + 1], &freq[k], l);
1327 memmove(&son[k + 1], &son[k], l);
1330 for(i = 0; i < TABLE_SIZE; i++) {
1331 if((k = son[i]) >= TABLE_SIZE) {
1334 prnt[k] = prnt[k + 1] = i;
1339 void DISK::update(int c)
1342 if(freq[ROOT_POSITION] == MAX_FREQ) {
1345 c = prnt[c + TABLE_SIZE];
1348 if(k > freq[l = c + 1]) {
1349 while(k > freq[++l]);
1355 if(i < TABLE_SIZE) {
1361 if(j < TABLE_SIZE) {
1368 while((c = prnt[c]) != 0);
1371 short DISK::decode_char()
1374 uint16 c = son[ROOT_POSITION];
1375 while(c < TABLE_SIZE) {
1376 if((ret = get_bit()) < 0) {
1387 short DISK::decode_position()
1391 if((bit = get_byte()) < 0) {
1395 c = (uint16)d_code[i] << 6;
1398 if((bit = get_bit()) < 0) {
1403 return (c | i & 0x3f);
1406 void DISK::init_decode()
1408 ibufcnt= ibufndx = bufcnt = getbuf = 0;
1411 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1414 ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1417 int DISK::decode(uint8 *buf, int len)
1421 for(count = 0; count < len;) {
1423 if((c = decode_char()) < 0) {
1427 *(buf++) = (uint8)c;
1428 text_buf[ptr++] = (uint8)c;
1429 ptr &= (STRING_BUFFER_SIZE - 1);
1432 if((pos = decode_position()) < 0) {
1435 bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1436 bufcnt = c - 255 + THRESHOLD;
1440 while(bufndx < bufcnt && count < len) {
1441 c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];
1442 *(buf++) = (uint8)c;
1444 text_buf[ptr++] = (uint8)c;
1445 ptr &= (STRING_BUFFER_SIZE - 1);
1448 if(bufndx >= bufcnt) {
1449 bufndx = bufcnt = 0;
1456 // imagedisk image decoder
1466 bool DISK::imagedisk_to_d88()
1473 fi->Fseek(0, FILEIO_SEEK_SET);
1475 while((tmp = fi->Fgetc()) != 0x1a) {
1484 // create d88 header
1485 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1486 _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1487 d88_hdr.protect = 0; // non-protected
1488 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1491 int trkptr = sizeof(d88_hdr_t);
1492 int trkcnt = 0, mode;
1494 for(int t = 0; t < 164; t++) {
1495 // check end of file
1496 if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {
1501 // check track header
1503 mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps
1508 d88_hdr.trkptr[t] = trkptr;
1511 uint8 c[64], h[64], r[64];
1512 fi->Fread(r, trk.nsec, 1);
1513 if(trk.head & 0x80) {
1514 fi->Fread(c, trk.nsec, 1);
1516 memset(c, trk.cyl, sizeof(c));
1518 if(trk.head & 0x40) {
1519 fi->Fread(h, trk.nsec, 1);
1521 memset(h, trk.head & 1, sizeof(h));
1524 // read sectors in this track
1525 for(int i = 0; i < trk.nsec; i++) {
1526 // create d88 sector header
1527 int sectype = fi->Fgetc();
1531 memset(&d88_sct, 0, sizeof(d88_sct_t));
1535 d88_sct.n = trk.size;
1536 d88_sct.nsec = trk.nsec;
1537 d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;
1538 d88_sct.del = (sectype == 3 || sectype == 4 || sectype == 7 || sectype == 8) ? 0x10 : 0;
1539 d88_sct.stat = (sectype == 5 || sectype == 6 || sectype == 7 || sectype == 8) ? 0xb0 : d88_sct.del;
1540 d88_sct.size = secsize[trk.size & 7];
1542 // create sector image
1544 if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {
1546 fi->Fread(dst, d88_sct.size, 1);
1547 } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {
1549 int tmp = fi->Fgetc();
1550 memset(dst, tmp, d88_sct.size);
1552 d88_sct.stat = 0xf0; // data mark missing
1557 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1558 COPYBUFFER(dst, d88_sct.size);
1559 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1562 d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1563 d88_hdr.size = trkptr;
1564 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1568 // cpdread image decoder (from MESS formats/dsk_dsk.c)
1570 bool DISK::cpdread_to_d88(int extended)
1576 // get cylinder number and side number
1577 memcpy(tmp_buffer, buffer, file_size.d);
1578 int ncyl = tmp_buffer[0x30];
1579 int nside = tmp_buffer[0x31];
1584 // create d88 header
1585 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1586 _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDRead");
1587 d88_hdr.protect = 0; // non-protected
1588 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1591 int trkofs = 0x100, trkofs_ptr = 0x34;
1592 int trkptr = sizeof(d88_hdr_t);
1594 for(int c = 0; c < ncyl; c++) {
1595 for(int h = 0; h < nside; h++) {
1596 // read sectors in this track
1597 uint8 *track_info = tmp_buffer + trkofs;
1598 int cyl = track_info[0x10];
1599 int side = track_info[0x11] & 1;
1600 int nsec = track_info[0x15];
1601 int size = 1 << (track_info[0x14] + 7); // standard
1602 int sctofs = trkofs + 0x100;
1607 d88_hdr.trkptr[2 * cyl + side] = trkptr;
1609 for(int s = 0; s < nsec; s++) {
1611 uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;
1613 size = sector_info[6] + sector_info[7] * 256;
1616 // create d88 sector header
1617 memset(&d88_sct, 0, sizeof(d88_sct_t));
1618 d88_sct.c = sector_info[0];
1619 d88_sct.h = sector_info[1];
1620 d88_sct.r = sector_info[2];
1621 d88_sct.n = sector_info[3];
1622 d88_sct.nsec = nsec;
1624 d88_sct.del = (sector_info[5] == 0xb2) ? 0x10 : 0;
1625 d88_sct.stat = (size == 0) ? 0xf0 : (sector_info[5] == 0xb5) ? 0xb0 : d88_sct.del;
1626 d88_sct.size = size;
1629 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1630 COPYBUFFER(tmp_buffer + sctofs, size);
1631 trkptr += sizeof(d88_sct_t) + size;
1637 trkofs += tmp_buffer[trkofs_ptr++] * 256;
1639 trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1643 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1644 d88_hdr.size = trkptr;
1645 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1649 // solid image decoder
1651 bool DISK::solid_to_d88(int type, int ncyl, int nside, int nsec, int size)
1659 // create d88 header
1660 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1661 _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "STANDARD");
1662 d88_hdr.protect = 0; // non-protected
1663 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
1665 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1668 for(int i = 0; i < 8; i++) {
1669 if(size == (128 << i)) {
1676 int trkptr = sizeof(d88_hdr_t);
1677 for(int c = 0; c < ncyl; c++) {
1678 for(int h = 0; h < nside; h++) {
1679 d88_hdr.trkptr[t++] = trkptr;
1684 // read sectors in this track
1685 for(int s = 0; s < nsec; s++) {
1686 // create d88 sector header
1687 memset(&d88_sct, 0, sizeof(d88_sct_t));
1692 d88_sct.nsec = nsec;
1696 d88_sct.size = size;
1698 // create sector image
1700 memset(dst, 0xe5, sizeof(dst));
1701 fi->Fread(dst, size, 1);
1704 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1705 COPYBUFFER(dst, size);
1706 trkptr += sizeof(d88_sct_t) + size;
1710 d88_hdr.size = trkptr;
1711 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1715 #define STATE_VERSION 6
1717 void DISK::save_state(FILEIO* state_fio)
1719 state_fio->FputUint32(STATE_VERSION);
1721 state_fio->Fwrite(buffer, sizeof(buffer), 1);
1722 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
1723 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
1724 state_fio->FputUint32(file_size.d);
1725 state_fio->FputInt32(file_bank);
1726 state_fio->FputUint32(crc32);
1727 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
1728 state_fio->FputBool(inserted);
1729 state_fio->FputBool(ejected);
1730 state_fio->FputBool(write_protected);
1731 state_fio->FputBool(changed);
1732 state_fio->FputUint8(media_type);
1733 state_fio->FputBool(is_solid_image);
1734 state_fio->FputBool(is_fdi_image);
1735 state_fio->FputBool(is_1dd_image);
1736 state_fio->FputInt32(is_special_disk);
1737 state_fio->Fwrite(track, sizeof(track), 1);
1738 state_fio->FputInt32(sector_num.sd);
1739 state_fio->FputBool(invalid_format);
1740 state_fio->FputBool(no_skew);
1741 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
1742 state_fio->Fwrite(id_position, sizeof(id_position), 1);
1743 state_fio->Fwrite(data_position, sizeof(data_position), 1);
1744 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
1745 state_fio->FputInt32(sector_size.sd);
1746 state_fio->Fwrite(id, sizeof(id), 1);
1747 state_fio->FputUint8(density);
1748 state_fio->FputBool(deleted);
1749 state_fio->FputBool(addr_crc_error);
1750 state_fio->FputBool(data_crc_error);
1751 state_fio->FputUint8(drive_type);
1752 state_fio->FputInt32(drive_rpm);
1753 state_fio->FputBool(drive_mfm);
1756 bool DISK::load_state(FILEIO* state_fio)
1758 if(state_fio->FgetUint32() != STATE_VERSION) {
1761 state_fio->Fread(buffer, sizeof(buffer), 1);
1762 state_fio->Fread(orig_path, sizeof(orig_path), 1);
1763 state_fio->Fread(dest_path, sizeof(dest_path), 1);
1764 file_size.d = state_fio->FgetUint32();
1765 file_bank = state_fio->FgetInt32();
1766 crc32 = state_fio->FgetUint32();
1767 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
1768 inserted = state_fio->FgetBool();
1769 ejected = state_fio->FgetBool();
1770 write_protected = state_fio->FgetBool();
1771 changed = state_fio->FgetBool();
1772 media_type = state_fio->FgetUint8();
1773 is_solid_image = state_fio->FgetBool();
1774 is_fdi_image = state_fio->FgetBool();
1775 is_1dd_image = state_fio->FgetBool();
1776 is_special_disk = state_fio->FgetInt32();
1777 state_fio->Fread(track, sizeof(track), 1);
1778 sector_num.sd = state_fio->FgetInt32();
1779 invalid_format = state_fio->FgetBool();
1780 no_skew = state_fio->FgetBool();
1781 state_fio->Fread(sync_position, sizeof(sync_position), 1);
1782 state_fio->Fread(id_position, sizeof(id_position), 1);
1783 state_fio->Fread(data_position, sizeof(data_position), 1);
1784 int offset = state_fio->FgetInt32();
1785 sector = (offset != -1) ? buffer + offset : NULL;
1786 sector_size.sd = state_fio->FgetInt32();
1787 state_fio->Fread(id, sizeof(id), 1);
1788 density = state_fio->FgetUint8();
1789 deleted = state_fio->FgetBool();
1790 addr_crc_error = state_fio->FgetBool();
1791 data_crc_error = state_fio->FgetBool();
1792 drive_type = state_fio->FgetUint8();
1793 drive_rpm = state_fio->FgetInt32();
1794 drive_mfm = state_fio->FgetBool();