2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
11 #include "../fileio.h"
14 #define local_path(x) create_local_path(x)
16 #define local_path(x) (x)
20 static const uint16 crc_table[256] = {
21 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
22 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
23 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
24 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
25 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
26 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
27 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
28 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
29 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
30 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
31 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
32 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
33 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
34 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
35 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
36 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
39 static const int secsize[8] = {
40 128, 256, 512, 1024, 2048, 4096, 8192, 16384
43 static uint8 tmp_buffer[DISK_BUFFER_SIZE];
45 // physical format table for solid image
48 int ncyl, nside, nsec, size;
55 static const fd_format_t fd_formats[] = {
57 { MEDIA_TYPE_2D, 40, 1, 16, 256, MFM }, // 1D 160KB
58 #elif defined(_SMC70) || defined(_SMC777)
59 { MEDIA_TYPE_2DD, 70, 1, 16, 256, MFM }, // 1DD 280KB
60 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
61 { MEDIA_TYPE_2D, 40, 2, 16, 256, MFM }, // 2D 320KB
63 { MEDIA_TYPE_2D, 40, 2, 18, 256, MFM }, // 2D 360KB
64 #elif defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
65 { MEDIA_TYPE_2DD, 80, 2, 16, 256, MFM }, // 2DD 640KB
67 { MEDIA_TYPE_2D, 35, 1, 16, 128, FM }, // 1S 70KB
68 { MEDIA_TYPE_2D, 35, 2, 16, 128, FM }, // 2S 140KB
69 { MEDIA_TYPE_2DD, 77, 1, 26, 128, FM }, // 1S 250KB
70 { MEDIA_TYPE_2D, 40, 1, 8, 512, MFM }, // 1D 160KB
71 { MEDIA_TYPE_2D, 40, 1, 9, 512, MFM }, // 1D 180KB
72 { MEDIA_TYPE_2D, 40, 1, 10, 512, MFM }, // 1D 200KB
73 //#if defined(SUPPORT_MEDIA_TYPE_1DD)
74 // { MEDIA_TYPE_2DD, 70, 1, 8, 512, MFM }, // 1DD 280KB
75 // { MEDIA_TYPE_2DD, 70, 1, 9, 512, MFM }, // 1DD 315KB
76 // { MEDIA_TYPE_2DD, 70, 1, 10, 512, MFM }, // 1DD 350KB
77 // { MEDIA_TYPE_2DD, 80, 1, 8, 512, MFM }, // 1DD 320KB
78 // { MEDIA_TYPE_2DD, 80, 1, 9, 512, MFM }, // 1DD 360KB
79 // { MEDIA_TYPE_2DD, 80, 1, 10, 512, MFM }, // 1DD 400KB
81 { MEDIA_TYPE_2D, 35, 2, 8, 512, MFM }, // 2D 280KB
82 { MEDIA_TYPE_2D, 35, 2, 9, 512, MFM }, // 2D 315KB
83 { MEDIA_TYPE_2D, 35, 2, 10, 512, MFM }, // 2D 350KB
84 { MEDIA_TYPE_2D, 40, 2, 8, 512, MFM }, // 2D 320KB
85 { MEDIA_TYPE_2D, 40, 2, 9, 512, MFM }, // 2D 360KB
86 { MEDIA_TYPE_2D, 40, 2, 10, 512, MFM }, // 2D 400KB
88 { MEDIA_TYPE_2DD, 80, 2, 8, 512, MFM }, // 2DD 640KB
89 { MEDIA_TYPE_2DD, 80, 2, 9, 512, MFM }, // 2DD 720KB
90 { MEDIA_TYPE_2DD, 81, 2, 9, 512, MFM }, // 2DD 729KB, ASCII MSX
91 { MEDIA_TYPE_2DD, 80, 2, 10, 512, MFM }, // 2DD 800KB
92 { MEDIA_TYPE_2HD, 77, 2, 26, 256, MFM }, // 2HD 1001KB, MITSUBISHI/IBM
93 { MEDIA_TYPE_2HD, 80, 2, 15, 512, MFM }, // 2HC 1200KB, TOSHIBA/IBM
94 { MEDIA_TYPE_2HD, 77, 2, 8, 1024, MFM }, // 2HD 1232KB, NEC
95 { MEDIA_TYPE_144, 80, 2, 18, 512, MFM }, // 2HD 1440KB
96 { MEDIA_TYPE_144, 80, 2, 21, 512, MFM }, // 2HD 1680KB
97 { MEDIA_TYPE_144, 82, 2, 21, 512, MFM }, // 2HD 1722KB
98 { MEDIA_TYPE_144, 80, 2, 36, 512, MFM }, // 2ED 2880KB
102 #define IS_VALID_TRACK(offset) ((offset) >= 0x20 && (offset) < sizeof(buffer))
104 void DISK::open(const _TCHAR* file_path, int bank)
106 // check current disk image
108 if(_tcsicmp(orig_path, file_path) == 0 && file_bank == bank) {
116 memset(buffer, 0, sizeof(buffer));
118 write_protected = false;
119 media_type = MEDIA_TYPE_UNK;
120 is_solid_image = is_fdi_image = is_1dd_image = false;
121 trim_required = false;
122 track_mfm = drive_mfm;
125 FILEIO *fio = new FILEIO();
126 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
127 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
128 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
130 file_size.d = fio->FileLength();
131 fio->Fseek(0, FILEIO_SEEK_SET);
133 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
136 for(int i = 0; i < bank; i++) {
137 fio->Fseek(offset + 0x1c, SEEK_SET);
138 offset += fio->FgetUint32_LE();
140 fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
141 file_size.d = fio->FgetUint32_LE();
142 fio->Fseek(offset, FILEIO_SEEK_SET);
143 fio->Fread(buffer, file_size.d, 1);
145 if(check_file_extension(file_path, _T(".1dd"))) {
147 media_type = MEDIA_TYPE_2DD;
149 inserted = changed = true;
150 // trim_required = true;
152 // fix sector number from big endian to little endian
153 for(int trkside = 0; trkside < 164; trkside++) {
155 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
157 if(!IS_VALID_TRACK(offset.d)) {
160 uint8* t = buffer + offset.d;
161 pair sector_num, data_size;
162 sector_num.read_2bytes_le_from(t + 4);
163 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
165 sector_num.read_2bytes_be_from(t + 4);
166 sector_num.write_2bytes_le_to(t + 4);
168 for(int i = 0; i < sector_num.sd; i++) {
170 sector_num.write_2bytes_le_to(t + 4);
172 data_size.read_2bytes_le_from(t + 14);
173 t += data_size.sd + 0x10;
176 } else if(check_file_extension(file_path, _T(".td0"))) {
179 inserted = changed = teledisk_to_d88(fio);
180 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
182 // failed to convert the disk image
184 } else if(check_file_extension(file_path, _T(".imd"))) {
187 inserted = changed = imagedisk_to_d88(fio);
188 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
190 // failed to convert the disk image
192 } else if(check_file_extension(file_path, _T(".dsk"))) {
195 inserted = changed = cpdread_to_d88(fio);
196 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
198 // failed to convert the disk image
200 } else if(check_file_extension(file_path, _T(".2d")) && file_size.d == 40 * 2 * 16 * 256) {
201 // 2d image for SHARP X1 series
202 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true);
203 } else if(check_file_extension(file_path, _T(".img")) && file_size.d == 70 * 1 * 16 * 256) {
204 // img image for SONY SMC-70/777 series
205 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true);
206 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
207 // sf7 image for SEGA SC-3000 + SF-7000
208 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true);
211 // check solid image file format
212 bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
213 for(int i = 0;; i++) {
214 const fd_format_t *p = &fd_formats[i];
218 int len = p->ncyl * p->nside * p->nsec * p->size;
219 // 4096 bytes: FDI header ???
220 if(file_size.d == len + (is_fdi_tmp ? 4096 : 0)) {
221 fio->Fseek(0, FILEIO_SEEK_SET);
224 fio->Fread(fdi_header, 4096, 1);
228 int nside = p->nside;
231 #if defined(SUPPORT_MEDIA_TYPE_1DD)
232 if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
233 type = MEDIA_TYPE_2DD;
237 #elif defined(_ANY2D88)
238 if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
239 type = MEDIA_TYPE_2DD;
243 if(open_as_256 && (size == 512 || size == 1024)) {
248 // if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
249 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
250 inserted = changed = is_solid_image = true;
256 if(fio->IsOpened()) {
260 if(buffer[0x1a] != 0) {
262 write_protected = true;
264 crc32 = getcrc32(buffer, file_size.d);
266 if(media_type == MEDIA_TYPE_UNK) {
267 if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
268 for(int trkside = 0; trkside < 164; trkside++) {
270 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
272 if(!IS_VALID_TRACK(offset.d)) {
276 uint8 *t = buffer + offset.d;
277 pair sector_num, data_size;
278 sector_num.read_2bytes_le_from(t + 4);
279 data_size.read_2bytes_le_from(t + 14);
281 if(sector_num.sd >= 18 && data_size.sd == 512) {
282 media_type = MEDIA_TYPE_144;
289 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
290 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
291 if(media_type == MEDIA_TYPE_2D) {
293 pair offset, sector_num, data_size;
294 offset.read_4bytes_le_from(buffer + 0x20);
295 if(IS_VALID_TRACK(offset.d)) {
296 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
297 uint8* t = buffer + offset.d;
298 sector_num.read_2bytes_le_from(t + 4);
299 for(int i = 0; i < sector_num.sd; i++) {
300 data_size.read_2bytes_le_from(t + 14);
301 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
302 static const uint8 gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
303 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
304 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
307 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
308 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
309 static const uint8 deathforce[] ={
310 0x44, 0x45, 0x41, 0x54, 0x48, 0x46, 0x4f, 0x52,
311 0x43, 0x45, 0x2f, 0x37, 0x37, 0x41, 0x56, 0xf7,
312 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
313 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7,
316 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
317 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
320 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
321 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc" + $B6 + $FD + $05
322 static const uint8 psyoblade_ipl1[] ={
323 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
324 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
325 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
326 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
327 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
328 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
332 static const uint8 psyoblade_disk_1[] ={
333 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
334 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
335 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
336 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
338 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
339 static const uint8 psyoblade_disk_2[] ={
340 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
341 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
342 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
344 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
345 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
347 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
348 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
349 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
354 t += data_size.sd + 0x10;
358 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
359 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
360 if(media_type == MEDIA_TYPE_2D) {
363 offset.read_4bytes_le_from(buffer + 0x20);
364 if(IS_VALID_TRACK(offset.d)) {
365 // check first sector
366 static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
367 uint8 *t = buffer + offset.d;
368 #if defined(_X1TURBO) || defined(_X1TURBOZ)
369 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
370 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
373 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
374 is_special_disk = SPECIAL_DISK_X1_BATTEN;
389 trim_required = false;
391 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
393 if(/*!write_protected &&*/ file_size.d && getcrc32(buffer, file_size.d) != crc32) {
395 FILEIO* fio = new FILEIO();
396 int pre_size = 0, post_size = 0;
397 uint8 *pre_buffer = NULL, *post_buffer = NULL;
399 // is this d88 format ?
400 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
401 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
402 fio->Fseek(0, FILEIO_SEEK_END);
403 uint32 total_size = fio->Ftell(), offset = 0;
404 for(int i = 0; i < file_bank; i++) {
405 fio->Fseek(offset + 0x1c, SEEK_SET);
406 offset += fio->FgetUint32_LE();
408 if((pre_size = offset) > 0) {
409 pre_buffer = (uint8 *)malloc(pre_size);
410 fio->Fseek(0, FILEIO_SEEK_SET);
411 fio->Fread(pre_buffer, pre_size, 1);
413 fio->Fseek(offset + 0x1c, SEEK_SET);
414 offset += fio->FgetUint32_LE();
415 if((post_size = total_size - offset) > 0) {
416 post_buffer = (uint8 *)malloc(post_size);
417 fio->Fseek(offset, FILEIO_SEEK_SET);
418 fio->Fread(post_buffer, post_size, 1);
424 // is this solid image and was physical formatted ?
426 bool formatted = false;
429 for(int trkside = 0; trkside < 164; trkside++) {
431 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
433 if(!IS_VALID_TRACK(offset.d)) {
436 if(solid_nside == 1 && (trkside & 1) == 1) {
441 uint8* t = buffer + offset.d;
442 pair sector_num, data_size;
443 sector_num.read_2bytes_le_from(t + 4);
445 if(sector_num.sd != solid_nsec) {
448 for(int i = 0; i < sector_num.sd; i++) {
449 data_size.read_2bytes_le_from(t + 14);
450 if(data_size.sd != solid_size) {
453 if(t[6] != (solid_mfm ? 0 : 0x40)) {
456 t += data_size.sd + 0x10;
459 if(tracks != (solid_ncyl * solid_nside)) {
463 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
464 is_solid_image = false;
468 if((FILEIO::IsFileExists(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
469 _TCHAR tmp_path[_MAX_PATH];
470 my_stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
471 fio->Fopen(local_path(tmp_path), FILEIO_WRITE_BINARY);
473 if(fio->IsOpened()) {
475 fio->Fwrite(pre_buffer, pre_size, 1);
479 fio->Fwrite(fdi_header, 4096, 1);
481 for(int trkside = 0; trkside < 164; trkside++) {
483 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
485 if(!IS_VALID_TRACK(offset.d)) {
488 uint8* t = buffer + offset.d;
489 pair sector_num, data_size;
490 sector_num.read_2bytes_le_from(t + 4);
492 for(int i = 0; i < sector_num.sd; i++) {
493 data_size.read_2bytes_le_from(t + 14);
494 fio->Fwrite(t + 0x10, data_size.sd, 1);
495 t += data_size.sd + 0x10;
499 fio->Fwrite(buffer, file_size.d, 1);
502 fio->Fwrite(post_buffer, post_size, 1);
516 inserted = write_protected = false;
518 sector_size.sd = sector_num.sd = 0;
523 void DISK::save_as_d88(const _TCHAR* file_path)
526 FILEIO* fio = new FILEIO();
527 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
529 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
530 for(int trk = 0; trk < 82; trk++) {
531 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
532 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
534 buffer[0x1b] = MEDIA_TYPE_2DD;
536 fio->Fwrite(buffer, file_size.d, 1);
544 bool DISK::get_track(int trk, int side)
546 sector_size.sd = sector_num.sd = 0;
547 invalid_format = false;
550 // disk not inserted or invalid media type
551 if(!(inserted && check_media_type())) {
556 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
557 if(!(0 <= trkside && trkside < 164)) {
564 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
566 if(!IS_VALID_TRACK(offset.d)) {
571 sector = buffer + offset.d;
572 sector_num.read_2bytes_le_from(sector + 4);
574 data_size.read_2bytes_le_from(sector + 14);
576 // create each sector position in track
578 if(sector_num.sd == 0) {
579 track_mfm = drive_mfm;
582 for(int i = 0; i < sector_num.sd; i++) {
583 data_size.read_2bytes_le_from(t + 14);
584 // t[6]: 0x00 = double-density, 0x40 = single-density
589 t += data_size.sd + 0x10;
592 int sync_size = track_mfm ? 12 : 6;
593 int am_size = track_mfm ? 3 : 0;
594 int gap0_size = track_mfm ? 80 : 40;
595 int gap1_size = track_mfm ? 50 : 26;
596 int gap2_size = track_mfm ? 22 : 11;
597 int gap3_size = 0, gap4_size;
599 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
601 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
602 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
603 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
605 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
606 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
607 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
611 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
612 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
613 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
615 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
616 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
617 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
622 int total = sync_size + (am_size + 1);
624 for(int i = 0; i < sector_num.sd; i++) {
625 data_size.read_2bytes_le_from(t + 14);
626 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
627 if(data_size.sd > 0) {
628 total += sync_size + (am_size + 1);
629 total += data_size.sd + 2;
631 // if(t[2] != i + 1) {
634 t += data_size.sd + 0x10;
637 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (sector_num.sd + 1);
639 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
641 if(gap3_size < 8 || gap4_size < 8) {
642 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + sector_num.sd + 1);
643 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd;
645 if(gap3_size < 8 || gap4_size < 8) {
646 gap0_size = gap1_size = gap3_size = gap4_size = 32;
647 invalid_format = true;
649 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
652 total = preamble_size;
653 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
655 for(int i = 0; i < sector_num.sd; i++) {
656 data_size.read_2bytes_le_from(t + 14);
658 total = preamble_size + (get_track_size() - preamble_size - gap4_size) * i / sector_num.sd;
660 sync_position[i] = total;
662 am1_position[i] = total;
663 total += am_size + 1;
664 id_position[i] = total;
665 total += (4 + 2) + gap2_size;
666 if(data_size.sd > 0) {
667 total += sync_size + (am_size + 1);
668 data_position[i] = total;
669 total += data_size.sd + 2;
671 data_position[i] = total; // FIXME
674 t += data_size.sd + 0x10;
679 bool DISK::make_track(int trk, int side)
681 int track_size = get_track_size();
683 if(!get_track(trk, side)) {
684 // create a dummy track
685 for(int i = 0; i < track_size; i++) {
692 int sync_size = track_mfm ? 12 : 6;
693 int am_size = track_mfm ? 3 : 0;
694 int gap2_size = track_mfm ? 22 : 11;
695 uint8 gap_data = track_mfm ? 0x4e : 0xff;
698 memset(track, gap_data, track_size);
699 int q = sync_position[array_length(sync_position) - 1];
702 for(int i = 0; i < sync_size; i++) {
706 for(int i = 0; i < am_size; i++) {
714 for(int i = 0; i < sector_num.sd; i++) {
716 data_size.read_2bytes_le_from(t + 14);
717 int p = sync_position[i];
720 for(int j = 0; j < sync_size; j++) {
721 if(p < track_size) track[p++] = 0x00;
724 for(int j = 0; j < am_size; j++) {
725 if(p < track_size) track[p++] = 0xa1;
727 if(p < track_size) track[p++] = 0xfe;
729 if(p < track_size) track[p++] = t[0];
730 if(p < track_size) track[p++] = t[1];
731 if(p < track_size) track[p++] = t[2];
732 if(p < track_size) track[p++] = t[3];
734 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
735 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
736 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
737 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
738 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
739 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
741 for(int j = 0; j < gap2_size; j++) {
742 if(p < track_size) track[p++] = gap_data;
745 if(data_size.sd > 0) {
747 for(int j = 0; j < sync_size; j++) {
748 if(p < track_size) track[p++] = 0x00;
751 for(int j = 0; j < am_size; j++) {
752 if(p < track_size) track[p++] = 0xa1;
754 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
757 for(int j = 0; j < data_size.sd; j++) {
758 if(p < track_size) track[p++] = t[0x10 + j];
759 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
761 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
762 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
764 t += data_size.sd + 0x10;
769 bool DISK::get_sector(int trk, int side, int index)
771 sector_size.sd = sector_num.sd = 0;
774 // disk not inserted or invalid media type
775 if(!(inserted && check_media_type())) {
780 if(trk == -1 && side == -1) {
784 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
785 if(!(0 <= trkside && trkside < 164)) {
789 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
791 if(!IS_VALID_TRACK(offset.d)) {
796 uint8* t = buffer + offset.d;
797 sector_num.read_2bytes_le_from(t + 4);
799 if(index >= sector_num.sd) {
804 for(int i = 0; i < index; i++) {
806 data_size.read_2bytes_le_from(t + 14);
807 t += data_size.sd + 0x10;
813 void DISK::set_sector_info(uint8 *t)
821 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
822 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
823 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
824 crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
825 id[4] = (crc >> 8) & 0xff;
826 id[5] = (crc >> 0) & 0xff;
827 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
828 // t[6]: 0x00 = double-density, 0x40 = single-density
829 // t[7]: 0x00 = normal, 0x10 = deleted mark
830 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
832 deleted = (t[7] != 0);
834 // if(ignore_crc()) {
835 // addr_crc_error = false;
836 // data_crc_error = false;
838 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
839 data_crc_error = ((t[8] & 0xf0) == 0xb0);
842 sector_size.read_2bytes_le_from(t + 14);
845 void DISK::set_deleted(bool value)
848 uint8 *t = sector - 0x10;
849 t[7] = value ? 0x10 : 0;
850 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
851 t[8] = (t[8] & 0x0f) | t[7];
857 void DISK::set_data_crc_error(bool value)
860 uint8 *t = sector - 0x10;
861 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
863 data_crc_error = value;
866 void DISK::set_data_mark_missing()
869 uint8 *t = sector - 0x10;
870 t[8] = (t[8] & 0x0f) | 0xf0;
874 //addr_crc_error = false;
875 data_crc_error = false;
878 bool DISK::format_track(int trk, int side)
880 // disk not inserted or invalid media type
881 if(!(inserted && check_media_type())) {
886 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
887 if(!(0 <= trkside && trkside < 164)) {
891 // create new empty track
894 trim_required = false;
896 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
898 offset.d = DISK_BUFFER_SIZE;
899 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
901 trim_required = true;
903 track_mfm = drive_mfm;
908 void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool data_crc_error, uint8 fill_data, int length)
910 uint8* t = buffer + DISK_BUFFER_SIZE;
913 for(int i = 0; i < (sector_num.sd - 1); i++) {
914 t[4] = sector_num.b.l;
915 t[5] = sector_num.b.h;
917 data_size.read_2bytes_le_from(t + 14);
918 t += data_size.sd + 0x10;
924 t[4] = sector_num.b.l;
925 t[5] = sector_num.b.h;
926 t[6] = track_mfm ? 0 : 0x40;
927 t[7] = deleted ? 0x10 : 0;
928 t[8] = data_crc_error ? 0xb0 : t[7];
929 t[14] = (length >> 0) & 0xff;
930 t[15] = (length >> 8) & 0xff;
931 memset(t + 16, fill_data, length);
936 void DISK::sync_buffer()
940 trim_required = false;
944 void DISK::trim_buffer()
946 int max_tracks = 164;
947 uint32 dest_offset = 0x2b0;
950 memset(tmp_buffer, 0, sizeof(tmp_buffer));
951 memcpy(tmp_buffer, buffer, 0x20);
954 for(int trkside = 0; trkside < 164; trkside++) {
956 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
957 if(src_trk_offset.d != 0) {
959 if(src_trk_offset.d < 0x2b0) {
960 max_tracks = (src_trk_offset.d - 0x20) >> 2;
963 if(src_trk_offset.d != 0x2b0) {
964 max_tracks = (src_trk_offset.d - 0x20) >> 2;
965 if(max_tracks > 164) {
966 dest_offset = 0x20 + max_tracks * 4);
975 for(int trkside = 0; trkside < max_tracks; trkside++) {
977 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
979 pair dest_trk_offset;
980 dest_trk_offset.d = 0;
982 if(IS_VALID_TRACK(src_trk_offset.d)) {
983 uint8* t = buffer + src_trk_offset.d;
984 pair sector_num, data_size;
985 sector_num.read_2bytes_le_from(t + 4);
986 if(sector_num.sd != 0) {
987 dest_trk_offset.d = dest_offset;
988 for(int i = 0; i < sector_num.sd; i++) {
989 data_size.read_2bytes_le_from(t + 14);
990 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
991 dest_offset += data_size.sd + 0x10;
992 t += data_size.sd + 0x10;
996 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1000 file_size.d = dest_offset;
1001 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1003 memset(buffer, 0, sizeof(buffer));
1004 // memcpy(buffer, tmp_buffer, file_size.d);
1005 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1006 //memcpy(buffer, tmp_buffer, (file_size.d > sizeof(buffer)) ? sizeof(buffer) : file_size.d);
1011 if(drive_rpm != 0) {
1013 } else if(inserted) {
1014 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1016 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1020 int DISK::get_track_size()
1023 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
1024 if(is_special_disk == SPECIAL_DISK_FM7_DEATHFORCE) {
1025 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6300 : 3100;
1028 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1030 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1034 double DISK::get_usec_per_track()
1036 return 1000000.0 / (get_rpm() / 60.0);
1039 double DISK::get_usec_per_bytes(int bytes)
1041 #if defined(_FM77AV_VARIANTS)
1042 if(is_special_disk == SPECIAL_DISK_FM77AV_PSYOBLADE) {
1043 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0) * 2.2) * bytes;
1046 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1049 int DISK::get_bytes_per_usec(double usec)
1051 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1054 bool DISK::check_media_type()
1056 switch(drive_type) {
1058 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1059 defined(_FM77AV20) || defined(_FM77AV20EX)
1060 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1062 return (media_type == MEDIA_TYPE_2D);
1064 case DRIVE_TYPE_2DD:
1065 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1066 case DRIVE_TYPE_2HD:
1067 return (media_type == MEDIA_TYPE_2HD);
1068 case DRIVE_TYPE_144:
1069 return (media_type == MEDIA_TYPE_144);
1070 case DRIVE_TYPE_UNK:
1071 return true; // always okay
1078 #define COPYBUFFER(src, size) { \
1079 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1082 memcpy(buffer + file_size.d, (src), (size)); \
1083 file_size.d += (size); \
1098 uint8 dens, del, stat;
1103 // teledisk image decoder
1106 this teledisk image decoder is based on:
1108 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1109 LZSS coded by Haruhiko OKUMURA
1110 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1111 Edited and translated to English by Kenji RIKITAKE
1115 #define STRING_BUFFER_SIZE 4096
1116 #define LOOKAHEAD_BUFFER_SIZE 60
1118 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1119 #define TABLE_SIZE (N_CHAR * 2 - 1)
1120 #define ROOT_POSITION (TABLE_SIZE - 1)
1121 #define MAX_FREQ 0x8000
1123 static uint8 td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1124 static uint16 td_ptr;
1125 static uint16 td_bufcnt, td_bufndx, td_bufpos;
1126 static uint16 td_ibufcnt, td_ibufndx;
1127 static uint8 td_inbuf[512];
1128 static uint16 td_freq[TABLE_SIZE + 1];
1129 static short td_prnt[TABLE_SIZE + N_CHAR];
1130 static short td_son[TABLE_SIZE];
1131 static uint16 td_getbuf;
1132 static uint8 td_getlen;
1134 static const uint8 td_d_code[256] = {
1135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1137 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1138 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1139 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1140 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1141 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1142 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1143 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1144 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1145 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1146 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1147 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1148 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1149 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1150 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1152 static const uint8 td_d_len[256] = {
1153 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1154 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1155 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1156 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1157 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1158 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1159 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1160 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1161 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1162 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1163 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1164 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1165 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1166 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1167 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1168 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1171 static int td_next_word(FILEIO* fio)
1173 if(td_ibufndx >= td_ibufcnt) {
1174 td_ibufndx = td_ibufcnt = 0;
1175 memset(td_inbuf, 0, 512);
1176 for(int i = 0; i < 512; i++) {
1177 int d = fio->Fgetc();
1188 while(td_getlen <= 8) {
1189 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1195 static int td_get_bit(FILEIO* fio)
1197 if(td_next_word(fio) < 0) {
1200 short i = td_getbuf;
1203 return (i < 0) ? 1 : 0;
1206 static int td_get_byte(FILEIO* fio)
1208 if(td_next_word(fio) != 0) {
1211 uint16 i = td_getbuf;
1218 static void td_start_huff()
1221 for(i = 0; i < N_CHAR; i++) {
1223 td_son[i] = i + TABLE_SIZE;
1224 td_prnt[i + TABLE_SIZE] = i;
1227 while(j <= ROOT_POSITION) {
1228 td_freq[j] = td_freq[i] + td_freq[i + 1];
1230 td_prnt[i] = td_prnt[i + 1] = j;
1233 td_freq[TABLE_SIZE] = 0xffff;
1234 td_prnt[ROOT_POSITION] = 0;
1237 static void td_reconst()
1241 for(i = 0; i < TABLE_SIZE; i++) {
1242 if(td_son[i] >= TABLE_SIZE) {
1243 td_freq[j] = (td_freq[i] + 1) / 2;
1244 td_son[j] = td_son[i];
1248 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1250 f = td_freq[j] = td_freq[i] + td_freq[k];
1251 for(k = j - 1; f < td_freq[k]; k--);
1254 memmove(&td_freq[k + 1], &td_freq[k], l);
1256 memmove(&td_son[k + 1], &td_son[k], l);
1259 for(i = 0; i < TABLE_SIZE; i++) {
1260 if((k = td_son[i]) >= TABLE_SIZE) {
1263 td_prnt[k] = td_prnt[k + 1] = i;
1268 static void td_update(int c)
1271 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1274 c = td_prnt[c + TABLE_SIZE];
1277 if(k > td_freq[l = c + 1]) {
1278 while(k > td_freq[++l]);
1280 td_freq[c] = td_freq[l];
1284 if(i < TABLE_SIZE) {
1290 if(j < TABLE_SIZE) {
1297 while((c = td_prnt[c]) != 0);
1300 static short td_decode_char(FILEIO* fio)
1303 uint16 c = td_son[ROOT_POSITION];
1304 while(c < TABLE_SIZE) {
1305 if((ret = td_get_bit(fio)) < 0) {
1316 static short td_decode_position(FILEIO* fio)
1320 if((bit = td_get_byte(fio)) < 0) {
1324 c = (uint16)td_d_code[i] << 6;
1325 j = td_d_len[i] - 2;
1327 if((bit = td_get_bit(fio)) < 0) {
1332 return (c | i & 0x3f);
1335 static void td_init_decode()
1337 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1340 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1341 td_text_buf[i] = ' ';
1343 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1346 static int td_decode(FILEIO* fio, uint8 *buf, int len)
1350 for(count = 0; count < len;) {
1351 if(td_bufcnt == 0) {
1352 if((c = td_decode_char(fio)) < 0) {
1356 *(buf++) = (uint8)c;
1357 td_text_buf[td_ptr++] = (uint8)c;
1358 td_ptr &= (STRING_BUFFER_SIZE - 1);
1361 if((pos = td_decode_position(fio)) < 0) {
1364 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1365 td_bufcnt = c - 255 + THRESHOLD;
1369 while(td_bufndx < td_bufcnt && count < len) {
1370 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1371 *(buf++) = (uint8)c;
1373 td_text_buf[td_ptr++] = (uint8)c;
1374 td_ptr &= (STRING_BUFFER_SIZE - 1);
1377 if(td_bufndx >= td_bufcnt) {
1378 td_bufndx = td_bufcnt = 0;
1405 uint8 nsec, trk, head;
1414 bool DISK::teledisk_to_d88(FILEIO *fio)
1421 bool temporary = false;
1423 // check teledisk header
1424 fio->Fseek(0, FILEIO_SEEK_SET);
1425 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1426 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1427 // this image is compressed
1428 // decompress to the temporary file
1429 FILEIO* fio_tmp = new FILEIO();
1430 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1437 if((rd = td_decode(fio, obuf, 512)) > 0) {
1438 fio_tmp->Fwrite(obuf, rd, 1);
1446 // reopen the temporary file
1448 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1451 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1452 // this image is not compressed
1456 if(hdr.flag & 0x80) {
1458 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1459 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1462 // create d88 header
1466 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1467 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1468 d88_hdr.protect = 0; // non-protected
1471 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1474 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1475 fio->Fread(&trk, sizeof(td_trk_t), 1);
1476 while(trk.nsec != 0xff) {
1477 d88_hdr.trkptr[trkcnt++] = trkptr;
1478 if(hdr.sides == 1) {
1482 // read sectors in this track
1483 for(int i = 0; i < trk.nsec; i++) {
1484 uint8 buf[2048], dst[2048];
1485 memset(buf, 0, sizeof(buf));
1486 memset(dst, 0, sizeof(dst));
1488 // read sector header
1489 fio->Fread(&sct, sizeof(td_sct_t), 1);
1491 // create d88 sector header
1492 memset(&d88_sct, 0, sizeof(d88_sct_t));
1497 d88_sct.nsec = trk.nsec;
1498 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1499 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1500 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1501 d88_sct.size = secsize[sct.n & 3];
1503 // create sector image
1504 if(sct.ctrl & 0x30) {
1505 d88_sct.stat = 0xf0; // data mark missing
1508 // read sector source
1509 int len = fio->Fgetc();
1510 len += fio->Fgetc() * 256 - 1;
1511 int flag = fio->Fgetc(), d = 0;
1512 fio->Fread(buf, len, 1);
1516 memcpy(dst, buf, len);
1517 } else if(flag == 1) {
1519 len2.read_2bytes_le_from(buf);
1524 } else if(flag == 2) {
1525 for(int s = 0; s < len;) {
1526 int type = buf[s++];
1527 int len2 = buf[s++];
1530 dst[d++] = buf[s++];
1532 } else if(type < 5) {
1538 for(int j = 0; j < n; j++) {
1542 for(int j = 0; j < n; j++) {
1547 break; // unknown type
1551 break; // unknown flag
1556 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1557 COPYBUFFER(dst, d88_sct.size);
1558 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1561 fio->Fread(&trk, sizeof(td_trk_t), 1);
1563 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1564 d88_hdr.size = trkptr;
1565 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1568 FILEIO::RemoveFile(_T("teledisk.$$$"));
1573 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1575 bool DISK::imagedisk_to_d88(FILEIO *fio)
1577 int size = fio->FileLength();
1578 fio->Fseek(0, FILEIO_SEEK_SET);
1579 fio->Fread(tmp_buffer, size, 1);
1581 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1586 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1593 // create d88 header
1597 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1598 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1599 d88_hdr.protect = 0; // non-protected
1602 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1605 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1610 // check track header
1611 uint8 mode = tmp_buffer[pos++];
1612 uint8 track = tmp_buffer[pos++];
1613 uint8 head = tmp_buffer[pos++];
1614 uint8 sector_count = tmp_buffer[pos++];
1615 uint8 ssize = tmp_buffer[pos++];
1617 if(sector_count == 0) {
1623 uint32 actual_size = ssize < 7 ? 128 << ssize : 8192;
1626 const uint8 *snum = &tmp_buffer[pos];
1627 pos += sector_count;
1628 const uint8 *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1630 pos += sector_count;
1631 const uint8 *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1633 pos += sector_count;
1637 int trkside = track * 2 + (head & 1);
1639 if(trkcnt < trkside) {
1642 d88_hdr.trkptr[trkside] = trkptr;
1644 if(img_mode == -1) {
1645 img_mode = mode & 3;
1648 // read sectors in this track
1649 for(int i = 0; i < sector_count; i++) {
1650 // create d88 sector header
1651 uint8 stype = tmp_buffer[pos++];
1652 memset(&d88_sct, 0, sizeof(d88_sct_t));
1653 d88_sct.c = tnum ? tnum[i] : track;
1654 d88_sct.h = hnum ? hnum[i] : head;
1655 d88_sct.r = snum[i];
1657 d88_sct.nsec = sector_count;
1658 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1660 if(stype == 0 || stype > 8) {
1661 d88_sct.stat = 0xf0; // data mark missing
1664 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1665 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1666 d88_sct.size = actual_size;
1668 // create sector image
1669 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1670 memset(dst, tmp_buffer[pos++], actual_size);
1672 memcpy(dst, &tmp_buffer[pos], actual_size);
1673 pos += d88_sct.size;
1679 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1680 COPYBUFFER(dst, d88_sct.size);
1681 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1685 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1686 d88_hdr.size = trkptr;
1687 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1691 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1693 #define DSK_FORMAT_HEADER "MV - CPC"
1694 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1697 struct track_header {
1698 uint8 headertag[13];
1705 uint8 sector_size_code;
1706 uint8 number_of_sector;
1710 struct sector_header {
1714 uint8 sector_size_code;
1715 uint8 fdc_status_reg1;
1716 uint8 fdc_status_reg2;
1721 bool DISK::cpdread_to_d88(FILEIO *fio)
1723 bool extendformat = false;
1724 int image_size = fio->FileLength();
1726 fio->Fseek(0, FILEIO_SEEK_SET);
1727 fio->Fread(tmp_buffer, image_size, 1);
1729 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1730 extendformat = true;
1731 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1732 extendformat = false;
1737 int heads = tmp_buffer[0x31];
1742 int tracks = tmp_buffer[0x30];
1743 int track_offsets[84 * 2];
1744 bool track_offsets_error = false;
1746 int cnt = 0, tmp = 0x100;
1747 for(int i = 0; i < tracks * heads; i++) {
1748 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1751 track_offsets[cnt] = tmp;
1752 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1756 int cnt = 0, tmp = 0x100;
1757 for(int i = 0; i < tracks * heads; i++) {
1758 int length = tmp_buffer[0x34 + i] << 8;
1760 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1763 track_offsets[cnt] = tmp;
1766 track_offsets[cnt] = image_size;
1771 if(track_offsets_error) {
1772 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1773 // so I modified this code to search "Track-Info" at the top of track information block
1774 int cnt = 0, tmp = 0x100;
1775 for(int i = 0; i < tracks * heads; i++) {
1777 for(; tmp < image_size; tmp += 0x10) {
1778 if(found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0)) {
1783 track_offsets[cnt] = tmp;
1786 track_offsets[cnt] = image_size;
1792 // create d88 header
1796 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1797 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
1798 d88_hdr.protect = 0; // non-protected
1801 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1804 int total = 0, trkptr = sizeof(d88_hdr_t);
1806 for(int track = 0; track < tracks; track++) {
1807 for(int side = 0; side < heads; side++) {
1808 if(track_offsets[(track << 1) + side] >= image_size) {
1811 if((track << 1) + side < 164) {
1812 d88_hdr.trkptr[(track << 1) + side] = trkptr;
1816 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
1817 int pos = track_offsets[(track << 1) + side] + 0x100;
1818 for(int j = 0; j < tr.number_of_sector; j++) {
1819 sector_header sector;
1820 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
1822 // create d88 sector header
1823 memset(&d88_sct, 0, sizeof(d88_sct_t));
1824 d88_sct.c = sector.track;
1825 d88_sct.h = sector.side;
1826 d88_sct.r = sector.sector_id;
1827 d88_sct.n = sector.sector_size_code;
1828 d88_sct.nsec = tr.number_of_sector;
1830 d88_sct.size = sector.data_length;
1831 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
1833 d88_sct.size = 128 << tr.sector_size_code;
1834 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
1836 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
1837 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
1840 if((track << 1) + side < 164) {
1841 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1842 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
1843 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1845 total += d88_sct.size;
1848 pos += sector.data_length;
1850 pos += 128 << tr.sector_size_code;
1855 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1856 d88_hdr.size = trkptr;
1857 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1861 // solid image decoder
1863 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
1869 solid_nside = nside;
1874 // create d88 header
1878 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1879 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
1880 d88_hdr.protect = 0; // non-protected
1883 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1886 for(int i = 0; i < 8; i++) {
1887 if(size == (128 << i)) {
1894 int trkptr = sizeof(d88_hdr_t);
1896 for(int c = 0; c < ncyl; c++) {
1897 for(int h = 0; h < nside; h++) {
1898 d88_hdr.trkptr[t++] = trkptr;
1903 // read sectors in this track
1904 for(int s = 0; s < nsec; s++) {
1905 // create d88 sector header
1906 memset(&d88_sct, 0, sizeof(d88_sct_t));
1911 d88_sct.nsec = nsec;
1915 d88_sct.size = size;
1917 // create sector image
1919 memset(dst, 0xe5, sizeof(dst));
1920 fio->Fread(dst, size, 1);
1923 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1924 COPYBUFFER(dst, size);
1925 trkptr += sizeof(d88_sct_t) + size;
1929 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
1930 d88_hdr.size = trkptr;
1931 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1935 #define STATE_VERSION 10
1937 void DISK::save_state(FILEIO* state_fio)
1939 state_fio->FputUint32(STATE_VERSION);
1941 state_fio->Fwrite(buffer, sizeof(buffer), 1);
1942 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
1943 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
1944 state_fio->FputUint32(file_size.d);
1945 state_fio->FputInt32(file_bank);
1946 state_fio->FputUint32(crc32);
1947 state_fio->FputBool(trim_required);
1948 state_fio->FputBool(is_1dd_image);
1949 state_fio->FputBool(is_solid_image);
1950 state_fio->FputBool(is_fdi_image);
1951 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
1952 state_fio->FputInt32(solid_ncyl);
1953 state_fio->FputInt32(solid_nside);
1954 state_fio->FputInt32(solid_nsec);
1955 state_fio->FputInt32(solid_size);
1956 state_fio->FputBool(solid_mfm);
1957 state_fio->FputBool(inserted);
1958 state_fio->FputBool(ejected);
1959 state_fio->FputBool(write_protected);
1960 state_fio->FputBool(changed);
1961 state_fio->FputUint8(media_type);
1962 state_fio->FputInt32(is_special_disk);
1963 state_fio->Fwrite(track, sizeof(track), 1);
1964 state_fio->FputInt32(sector_num.sd);
1965 state_fio->FputBool(track_mfm);
1966 state_fio->FputBool(invalid_format);
1967 // state_fio->FputBool(no_skew);
1968 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
1969 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
1970 state_fio->Fwrite(id_position, sizeof(id_position), 1);
1971 state_fio->Fwrite(data_position, sizeof(data_position), 1);
1972 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
1973 state_fio->FputInt32(sector_size.sd);
1974 state_fio->Fwrite(id, sizeof(id), 1);
1975 state_fio->FputUint8(density);
1976 state_fio->FputBool(deleted);
1977 state_fio->FputBool(addr_crc_error);
1978 state_fio->FputBool(data_crc_error);
1979 state_fio->FputUint8(drive_type);
1980 state_fio->FputInt32(drive_rpm);
1981 state_fio->FputBool(drive_mfm);
1984 bool DISK::load_state(FILEIO* state_fio)
1986 if(state_fio->FgetUint32() != STATE_VERSION) {
1989 state_fio->Fread(buffer, sizeof(buffer), 1);
1990 state_fio->Fread(orig_path, sizeof(orig_path), 1);
1991 state_fio->Fread(dest_path, sizeof(dest_path), 1);
1992 file_size.d = state_fio->FgetUint32();
1993 file_bank = state_fio->FgetInt32();
1994 crc32 = state_fio->FgetUint32();
1995 trim_required = state_fio->FgetBool();
1996 is_1dd_image = state_fio->FgetBool();
1997 is_solid_image = state_fio->FgetBool();
1998 is_fdi_image = state_fio->FgetBool();
1999 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2000 solid_ncyl = state_fio->FgetInt32();
2001 solid_nside = state_fio->FgetInt32();
2002 solid_nsec = state_fio->FgetInt32();
2003 solid_size = state_fio->FgetInt32();
2004 solid_mfm = state_fio->FgetBool();
2005 inserted = state_fio->FgetBool();
2006 ejected = state_fio->FgetBool();
2007 write_protected = state_fio->FgetBool();
2008 changed = state_fio->FgetBool();
2009 media_type = state_fio->FgetUint8();
2010 is_special_disk = state_fio->FgetInt32();
2011 state_fio->Fread(track, sizeof(track), 1);
2012 sector_num.sd = state_fio->FgetInt32();
2013 track_mfm = state_fio->FgetBool();
2014 invalid_format = state_fio->FgetBool();
2015 // no_skew = state_fio->FgetBool();
2016 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2017 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2018 state_fio->Fread(id_position, sizeof(id_position), 1);
2019 state_fio->Fread(data_position, sizeof(data_position), 1);
2020 int offset = state_fio->FgetInt32();
2021 sector = (offset != -1) ? buffer + offset : NULL;
2022 sector_size.sd = state_fio->FgetInt32();
2023 state_fio->Fread(id, sizeof(id), 1);
2024 density = state_fio->FgetUint8();
2025 deleted = state_fio->FgetBool();
2026 addr_crc_error = state_fio->FgetBool();
2027 data_crc_error = state_fio->FgetBool();
2028 drive_type = state_fio->FgetUint8();
2029 drive_rpm = state_fio->FgetInt32();
2030 drive_mfm = state_fio->FgetBool();