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_t 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_t 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;
121 is_solid_image = is_fdi_image = is_1dd_image = false;
122 trim_required = false;
123 track_mfm = drive_mfm;
126 FILEIO *fio = new FILEIO();
127 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
128 my_tcscpy_s(orig_path, _MAX_PATH, file_path);
129 my_tcscpy_s(dest_path, _MAX_PATH, file_path);
131 file_size.d = fio->FileLength();
132 fio->Fseek(0, FILEIO_SEEK_SET);
134 if(check_file_extension(file_path, _T(".d88")) || check_file_extension(file_path, _T(".d77")) || check_file_extension(file_path, _T(".1dd"))) {
137 for(int i = 0; i < bank; i++) {
138 fio->Fseek(offset + 0x1c, SEEK_SET);
139 offset += fio->FgetUint32_LE();
141 fio->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
142 file_size.d = fio->FgetUint32_LE();
143 fio->Fseek(offset, FILEIO_SEEK_SET);
144 fio->Fread(buffer, file_size.d, 1);
146 if(check_file_extension(file_path, _T(".1dd"))) {
148 media_type = MEDIA_TYPE_2DD;
150 inserted = changed = true;
151 // trim_required = true;
153 // fix sector number from big endian to little endian
154 for(int trkside = 0; trkside < 164; trkside++) {
156 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
158 if(!IS_VALID_TRACK(offset.d)) {
161 uint8_t* t = buffer + offset.d;
162 pair_t sector_num, data_size;
163 sector_num.read_2bytes_le_from(t + 4);
164 bool is_be = (sector_num.b.l == 0 && sector_num.b.h >= 4);
166 sector_num.read_2bytes_be_from(t + 4);
167 sector_num.write_2bytes_le_to(t + 4);
169 for(int i = 0; i < sector_num.sd; i++) {
171 sector_num.write_2bytes_le_to(t + 4);
173 data_size.read_2bytes_le_from(t + 14);
174 t += data_size.sd + 0x10;
177 } else if(check_file_extension(file_path, _T(".td0"))) {
180 inserted = changed = teledisk_to_d88(fio);
181 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
183 // failed to convert the disk image
185 } else if(check_file_extension(file_path, _T(".imd"))) {
188 inserted = changed = imagedisk_to_d88(fio);
189 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
191 // failed to convert the disk image
193 } else if(check_file_extension(file_path, _T(".dsk"))) {
196 inserted = changed = cpdread_to_d88(fio);
197 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), file_path);
199 // failed to convert the disk image
201 } else if(check_file_extension(file_path, _T(".2d")) && file_size.d == 40 * 2 * 16 * 256) {
202 // 2d image for SHARP X1 series
203 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 2, 16, 256, true);
204 } else if(check_file_extension(file_path, _T(".img")) && file_size.d == 70 * 1 * 16 * 256) {
205 // img image for SONY SMC-70/777 series
206 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2DD, 70, 1, 16, 256, true);
207 } else if(check_file_extension(file_path, _T(".sf7")) && file_size.d == 40 * 1 * 16 * 256) {
208 // sf7 image for SEGA SC-3000 + SF-7000
209 inserted = changed = is_solid_image = solid_to_d88(fio, MEDIA_TYPE_2D, 40, 1, 16, 256, true);
212 // check solid image file format
213 bool is_fdi_tmp = check_file_extension(file_path, _T(".fdi"));
214 for(int i = 0;; i++) {
215 const fd_format_t *p = &fd_formats[i];
219 int len = p->ncyl * p->nside * p->nsec * p->size;
220 // 4096 bytes: FDI header ???
221 if(file_size.d == len + (is_fdi_tmp ? 4096 : 0)) {
222 fio->Fseek(0, FILEIO_SEEK_SET);
225 fio->Fread(fdi_header, 4096, 1);
229 int nside = p->nside;
232 #if defined(SUPPORT_MEDIA_TYPE_1DD)
233 if(type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
234 type = MEDIA_TYPE_2DD;
238 #elif defined(_ANY2D88)
239 if(open_as_1dd && type == MEDIA_TYPE_2D && nside == 2 && p->mfm) {
240 type = MEDIA_TYPE_2DD;
244 if(open_as_256 && (size == 512 || size == 1024)) {
249 // if(solid_to_d88(fio, p->type, p->ncyl, p->nside, p->nsec, p->size, p->mfm)) {
250 if(solid_to_d88(fio, type, ncyl, nside, nsec, size, p->mfm)) {
251 inserted = changed = is_solid_image = true;
257 if(fio->IsOpened()) {
263 // check loaded image
266 if(media_type == MEDIA_TYPE_UNK) {
267 if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
268 // check 1.2MB or 1.44MB
269 for(int trkside = 0; trkside < 164; trkside++) {
271 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
273 if(!IS_VALID_TRACK(offset.d)) {
277 uint8_t *t = buffer + offset.d;
278 pair_t sector_num, data_size;
279 sector_num.read_2bytes_le_from(t + 4);
280 data_size.read_2bytes_le_from(t + 14);
282 if(sector_num.sd >= 18 && data_size.sd == 512) {
283 media_type = MEDIA_TYPE_144;
290 // fix write protect flag
291 if(buffer[0x1a] != 0) {
293 write_protected = true;
296 // get crc32 for midification check
297 crc32 = get_crc32(buffer, file_size.d);
299 // check special disk image
300 #if defined(_FM7) || defined(_FM8) || defined(_FM77_VARIANTS) || defined(_FM77AV_VARIANTS)
301 // FIXME: ugly patch for FM-7 Gambler Jiko Chuushin Ha, DEATH FORCE and Psy-O-Blade
302 if(media_type == MEDIA_TYPE_2D) {
304 pair_t offset, sector_num, data_size;
305 offset.read_4bytes_le_from(buffer + 0x20);
306 if(IS_VALID_TRACK(offset.d)) {
307 // check the sector (c,h,r,n) = (0,0,7,1) or (0,0,f7,2)
308 uint8_t* t = buffer + offset.d;
309 sector_num.read_2bytes_le_from(t + 4);
310 for(int i = 0; i < sector_num.sd; i++) {
311 data_size.read_2bytes_le_from(t + 14);
312 if(is_special_disk == 0) {
313 if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 7 && t[3] == 1) {
314 static const uint8_t gambler[] = {0xb7, 0xde, 0xad, 0xdc, 0xdd, 0xcc, 0xde, 0xd7, 0xb1, 0x20, 0xbc, 0xde, 0xba, 0xc1, 0xad, 0xb3, 0xbc, 0xdd, 0xca};
315 if(memcmp((void *)(t + 0x30), gambler, sizeof(gambler)) == 0) {
316 is_special_disk = SPECIAL_DISK_FM7_GAMBLER;
319 } else if(data_size.sd == 0x200 && t[0] == 0 && t[1] == 0 && t[2] == 0xf7 && t[3] == 2) {
320 //"DEATHFORCE/77AV" + $f7*17 + $00 + $00
321 static const uint8_t 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,
328 if(memcmp((void *)(t + 0x10), deathforce, sizeof(deathforce)) == 0) {
329 is_special_disk = SPECIAL_DISK_FM7_DEATHFORCE;
332 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 1 && t[3] == 1) {
333 //$03 + $2D + "PSY-O-BLADE Copyright 1988 by T&E SOFT Inc." + $B6 + $FD + $05
334 static const uint8_t psyoblade_ipl1[] ={
335 0x03, 0x2d, 0x50, 0x53, 0x59, 0xa5, 0x4f, 0xa5,
336 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20, 0x20, 0x20,
337 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
338 0x74, 0x20, 0x31, 0x39, 0x38, 0x38, 0x20, 0x62,
339 0x79, 0x20, 0x54, 0x26, 0x45, 0x20, 0x53, 0x4f,
340 0x46, 0x54, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0xb6,
344 static const uint8_t psyoblade_disk_1[] ={
345 0xc3, 0x00, 0x01, 0x00, 0x1a, 0x50, 0x86, 0xff,
346 0xb7, 0xfd, 0x10, 0xb7, 0xfd, 0x0f, 0x30, 0x8c,
347 0x0e, 0x8d, 0x35, 0x30, 0x8c, 0x14, 0x8d, 0x30,
348 0x30, 0x8c, 0x14, 0x8d, 0x2b, 0x20, 0xfe, 0x0a,
350 //$00 + $00 + $03 + $14 + "PSY-O-BLADE DISK" + $B6 + $FD + $05
351 static const uint8_t psyoblade_disk_2[] ={
352 0x00, 0x00, 0x03, 0x14, 0x50, 0x53, 0x59, 0xa5,
353 0x4f, 0xa5, 0x42, 0x4c, 0x41, 0x44, 0x45, 0x20,
354 0x20, 0x20, 0x44, 0x49, 0x53, 0x4B, 0x20
356 if(memcmp((void *)(t + 0x58), psyoblade_ipl1, sizeof(psyoblade_ipl1)) == 0) {
357 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
359 } else if(memcmp((void *)(t + 0x10), psyoblade_disk_1, sizeof(psyoblade_disk_1)) == 0) {
360 if(memcmp((void *)(t + 0x40), psyoblade_disk_2, sizeof(psyoblade_disk_2)) == 0) {
361 is_special_disk = SPECIAL_DISK_FM77AV_PSYOBLADE;
365 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
366 static const uint8_t taiyoufm1[] = {
367 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
368 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
369 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
370 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
371 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
372 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
373 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
374 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
375 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
376 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
378 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
379 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
382 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
383 static const uint8_t taiyoufm2[] = {
384 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
385 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
386 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
387 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
388 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
389 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
390 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
391 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
393 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
394 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
398 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 3 && t[3] == 1) {
399 static const uint8_t taiyoufm1[] = {
400 0x10, 0xff, 0x04, 0x9f, 0x10, 0xce, 0xfc, 0xf4,
401 0x37, 0x20, 0x34, 0x20, 0x37, 0x36, 0x34, 0x36, //7 4 7646
402 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
403 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
404 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
405 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
406 0x37, 0x36, 0x34, 0x36, 0x37, 0x36, 0x34, 0x36, //76467646
407 0x10, 0xfe, 0x04, 0x9f, 0x1c, 0xef, 0x86, 0xff,
408 0xb7, 0xfc, 0xf8, 0x17, 0x03, 0x3d, 0x33, 0xc9,
409 0xdb, 0x9c, 0x35, 0x04, 0x5a, 0x26, 0xa0, 0xfe,
411 if(memcmp((void *)(t + 0x70), taiyoufm1, sizeof(taiyoufm1)) == 0) {
412 is_special_disk = SPECIAL_DISK_FM7_TAIYOU1;
415 } else if(data_size.sd == 0x100 && t[0] == 0 && t[1] == 0 && t[2] == 2 && t[3] == 1) {
416 static const uint8_t taiyoufm2[] = {
417 0x3d, 0x02, 0xa3, 0xd6, 0x01, 0xc7, 0x06, 0x86,
418 0x07, 0x00, 0x00, 0xc7, 0x06, 0xd4, 0x01, 0x00,
419 0x00, 0xb4, 0x19, 0xcd, 0x21, 0xfe, 0xc0, 0xa2,
420 0xda, 0x01, 0x06, 0xb9, 0x10, 0x00, 0xbb, 0x40,
421 0x00, 0x8e, 0xc3, 0xbb, 0x00, 0x00, 0xfe, 0x06,
422 0xd9, 0x01, 0x26, 0x80, 0xbf, 0x6c, 0x02, 0x00,
423 0x74, 0x03, 0x43, 0xe2, 0xf1, 0x07, 0xc6, 0x06,
424 0xdb, 0x01, 0x00, 0xbb, 0x80, 0x00, 0x80, 0x3f,
426 if(memcmp((void *)(t + 0x00), taiyoufm2, sizeof(taiyoufm2)) == 0) {
427 is_special_disk = SPECIAL_DISK_FM7_TAIYOU2;
431 t += data_size.sd + 0x10;
435 #elif defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
436 // FIXME: ugly patch for X1turbo ALPHA and X1 Batten Tanuki
437 if(media_type == MEDIA_TYPE_2D) {
440 offset.read_4bytes_le_from(buffer + 0x20);
441 if(IS_VALID_TRACK(offset.d)) {
442 // check first sector
443 static const uint8_t batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
444 uint8_t *t = buffer + offset.d;
445 #if defined(_X1TURBO) || defined(_X1TURBOZ)
446 // if(strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0) {
447 // is_special_disk = SPECIAL_DISK_X1TURBO_ALPHA;
450 if(memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0) {
451 is_special_disk = SPECIAL_DISK_X1_BATTEN;
465 trim_required = false;
467 buffer[0x1a] = write_protected ? 0x10 : 0; // mey be changed
469 if(/*!write_protected &&*/ file_size.d && get_crc32(buffer, file_size.d) != crc32) {
471 FILEIO* fio = new FILEIO();
472 int pre_size = 0, post_size = 0;
473 uint8_t *pre_buffer = NULL, *post_buffer = NULL;
475 // is this d88 format ?
476 if(check_file_extension(dest_path, _T(".d88")) || check_file_extension(dest_path, _T(".d77")) || check_file_extension(dest_path, _T(".1dd"))) {
477 if(fio->Fopen(dest_path, FILEIO_READ_BINARY)) {
478 fio->Fseek(0, FILEIO_SEEK_END);
479 uint32_t total_size = fio->Ftell(), offset = 0;
480 for(int i = 0; i < file_bank; i++) {
481 fio->Fseek(offset + 0x1c, SEEK_SET);
482 offset += fio->FgetUint32_LE();
484 if((pre_size = offset) > 0) {
485 pre_buffer = (uint8_t *)malloc(pre_size);
486 fio->Fseek(0, FILEIO_SEEK_SET);
487 fio->Fread(pre_buffer, pre_size, 1);
489 fio->Fseek(offset + 0x1c, SEEK_SET);
490 offset += fio->FgetUint32_LE();
491 if((post_size = total_size - offset) > 0) {
492 post_buffer = (uint8_t *)malloc(post_size);
493 fio->Fseek(offset, FILEIO_SEEK_SET);
494 fio->Fread(post_buffer, post_size, 1);
500 // is this solid image and was physical formatted ?
502 bool formatted = false;
505 for(int trkside = 0; trkside < 164; trkside++) {
507 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
509 if(!IS_VALID_TRACK(offset.d)) {
512 if(solid_nside == 1 && (trkside & 1) == 1) {
517 uint8_t* t = buffer + offset.d;
518 pair_t sector_num, data_size;
519 sector_num.read_2bytes_le_from(t + 4);
521 if(sector_num.sd != solid_nsec) {
524 for(int i = 0; i < sector_num.sd; i++) {
525 data_size.read_2bytes_le_from(t + 14);
526 if(data_size.sd != solid_size) {
529 if(t[6] != (solid_mfm ? 0 : 0x40)) {
532 t += data_size.sd + 0x10;
535 if(tracks != (solid_ncyl * solid_nside)) {
539 my_stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), orig_path);
540 is_solid_image = false;
544 if((FILEIO::IsFileExisting(dest_path) && FILEIO::IsFileProtected(dest_path)) || !fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
545 fio->Fopen(local_path(create_string(_T("temporary_saved_floppy_disk_#%d.d88"), drive_num)), FILEIO_WRITE_BINARY);
547 if(fio->IsOpened()) {
549 fio->Fwrite(pre_buffer, pre_size, 1);
553 fio->Fwrite(fdi_header, 4096, 1);
555 for(int trkside = 0; trkside < 164; trkside++) {
557 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
559 if(!IS_VALID_TRACK(offset.d)) {
562 uint8_t* t = buffer + offset.d;
563 pair_t sector_num, data_size;
564 sector_num.read_2bytes_le_from(t + 4);
566 for(int i = 0; i < sector_num.sd; i++) {
567 data_size.read_2bytes_le_from(t + 14);
568 fio->Fwrite(t + 0x10, data_size.sd, 1);
569 t += data_size.sd + 0x10;
573 fio->Fwrite(buffer, file_size.d, 1);
576 fio->Fwrite(post_buffer, post_size, 1);
590 inserted = write_protected = false;
592 sector_size.sd = sector_num.sd = 0;
597 void DISK::save_as_d88(const _TCHAR* file_path)
600 FILEIO* fio = new FILEIO();
601 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
603 memcpy(tmp_buffer, buffer + 0x20, 4 * 82);
604 for(int trk = 0; trk < 82; trk++) {
605 memcpy(buffer + 0x20 + (trk * 2 + 0) * 4, tmp_buffer + trk * 4, 4);
606 memset(buffer + 0x20 + (trk * 2 + 1) * 4, 0, 4);
608 buffer[0x1b] = MEDIA_TYPE_2DD;
610 fio->Fwrite(buffer, file_size.d, 1);
618 bool DISK::get_track(int trk, int side)
620 sector_size.sd = sector_num.sd = 0;
621 invalid_format = false;
624 // disk not inserted or invalid media type
625 if(!(inserted && check_media_type())) {
630 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
631 if(!(0 <= trkside && trkside < 164)) {
638 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
640 if(!IS_VALID_TRACK(offset.d)) {
645 sector = buffer + offset.d;
646 sector_num.read_2bytes_le_from(sector + 4);
648 data_size.read_2bytes_le_from(sector + 14);
650 // create each sector position in track
652 if(sector_num.sd == 0) {
653 track_mfm = drive_mfm;
656 for(int i = 0; i < sector_num.sd; i++) {
657 data_size.read_2bytes_le_from(t + 14);
658 // t[6]: 0x00 = double-density, 0x40 = single-density
663 t += data_size.sd + 0x10;
666 int sync_size = track_mfm ? 12 : 6;
667 int am_size = track_mfm ? 3 : 0;
668 int gap0_size = track_mfm ? 80 : 40;
669 int gap1_size = track_mfm ? 50 : 26;
670 int gap2_size = track_mfm ? 22 : 11;
671 int gap3_size = 0, gap4_size;
673 if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) {
675 if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54;
676 if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84;
677 if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116;
679 if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27;
680 if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42;
681 if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58;
685 if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51;
686 if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80;
687 if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116;
689 if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27;
690 if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42;
691 if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58;
696 int total = 0, valid_sector_num = 0;
698 for(int i = 0; i < sector_num.sd; i++) {
699 data_size.read_2bytes_le_from(t + 14);
700 sync_position[i] = total; // for invalid format case
701 total += sync_size + (am_size + 1) + (4 + 2) + gap2_size;
702 if(data_size.sd > 0) {
703 total += sync_size + (am_size + 1);
704 total += data_size.sd + 2;
707 //if(t[2] != i + 1) {
710 t += data_size.sd + 0x10;
712 total += sync_size + (am_size + 1); // sync in preamble
715 gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1);
717 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
719 if(gap3_size < 8 || gap4_size < 8) {
720 gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1);
721 gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num;
723 //printf("GAP3=%d GAP4=%d\n", gap3_size, gap4_size);
724 if(gap3_size < 8 || gap4_size < 8) {
725 gap0_size = gap1_size = gap3_size = gap4_size = 8;
726 //gap0_size = gap1_size = gap3_size = gap4_size = 32;
727 invalid_format = true;
730 int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size;
733 total -= sync_size + (am_size + 1);
734 for(int i = 0; i < sector_num.sd; i++) {
735 sync_position[i] *= get_track_size() - preamble_size - gap4_size;
736 sync_position[i] /= total;
740 total = preamble_size;
741 sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble
743 for(int i = 0; i < sector_num.sd; i++) {
744 data_size.read_2bytes_le_from(t + 14);
746 total = preamble_size + sync_position[i];
748 sync_position[i] = total;
750 am1_position[i] = total;
751 total += am_size + 1;
752 id_position[i] = total;
753 total += (4 + 2) + gap2_size;
754 if(data_size.sd > 0) {
755 total += sync_size + (am_size + 1);
756 data_position[i] = total;
757 total += data_size.sd + 2;
760 data_position[i] = total; // FIXME
762 t += data_size.sd + 0x10;
767 bool DISK::make_track(int trk, int side)
769 int track_size = get_track_size();
771 if(!get_track(trk, side)) {
772 // create a dummy track
773 for(int i = 0; i < track_size; i++) {
780 int sync_size = track_mfm ? 12 : 6;
781 int am_size = track_mfm ? 3 : 0;
782 int gap2_size = track_mfm ? 22 : 11;
783 uint8_t gap_data = track_mfm ? 0x4e : 0xff;
786 memset(track, gap_data, track_size);
787 int q = sync_position[array_length(sync_position) - 1];
790 for(int i = 0; i < sync_size; i++) {
794 for(int i = 0; i < am_size; i++) {
802 for(int i = 0; i < sector_num.sd; i++) {
804 data_size.read_2bytes_le_from(t + 14);
805 int p = sync_position[i];
808 for(int j = 0; j < sync_size; j++) {
809 if(p < track_size) track[p++] = 0x00;
812 for(int j = 0; j < am_size; j++) {
813 if(p < track_size) track[p++] = 0xa1;
815 if(p < track_size) track[p++] = 0xfe;
817 if(p < track_size) track[p++] = t[0];
818 if(p < track_size) track[p++] = t[1];
819 if(p < track_size) track[p++] = t[2];
820 if(p < track_size) track[p++] = t[3];
822 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
823 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
824 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
825 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
826 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
827 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
829 for(int j = 0; j < gap2_size; j++) {
830 if(p < track_size) track[p++] = gap_data;
833 if(data_size.sd > 0) {
835 for(int j = 0; j < sync_size; j++) {
836 if(p < track_size) track[p++] = 0x00;
839 for(int j = 0; j < am_size; j++) {
840 if(p < track_size) track[p++] = 0xa1;
842 if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
845 for(int j = 0; j < data_size.sd; j++) {
846 if(p < track_size) track[p++] = t[0x10 + j];
847 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0x10 + j]]);
849 if(p < track_size) track[p++] = (crc >> 8) & 0xff;
850 if(p < track_size) track[p++] = (crc >> 0) & 0xff;
852 t += data_size.sd + 0x10;
857 bool DISK::get_sector(int trk, int side, int index)
859 sector_size.sd = sector_num.sd = 0;
862 // disk not inserted or invalid media type
863 if(!(inserted && check_media_type())) {
868 if(trk == -1 && side == -1) {
872 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
873 if(!(0 <= trkside && trkside < 164)) {
877 offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
879 if(!IS_VALID_TRACK(offset.d)) {
884 uint8_t* t = buffer + offset.d;
885 sector_num.read_2bytes_le_from(t + 4);
887 if(index >= sector_num.sd) {
892 for(int i = 0; i < index; i++) {
894 data_size.read_2bytes_le_from(t + 14);
895 t += data_size.sd + 0x10;
901 void DISK::set_sector_info(uint8_t *t)
909 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[0]]);
910 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[1]]);
911 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[2]]);
912 crc = (uint16_t)((crc << 8) ^ crc_table[(uint8_t)(crc >> 8) ^ t[3]]);
913 id[4] = (crc >> 8) & 0xff;
914 id[5] = (crc >> 0) & 0xff;
915 // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT
916 // t[6]: 0x00 = double-density, 0x40 = single-density
917 // t[7]: 0x00 = normal, 0x10 = deleted mark
918 // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing
920 deleted = (t[7] != 0);
922 // if(ignore_crc()) {
923 // addr_crc_error = false;
924 // data_crc_error = false;
926 addr_crc_error = ((t[8] & 0xf0) == 0xa0);
927 data_crc_error = ((t[8] & 0xf0) == 0xb0);
930 sector_size.read_2bytes_le_from(t + 14);
933 void DISK::set_deleted(bool value)
936 uint8_t *t = sector - 0x10;
937 t[7] = value ? 0x10 : 0;
938 if((t[8] & 0xf0) == 0x00 || (t[8] & 0xf0) == 0x10) {
939 t[8] = (t[8] & 0x0f) | t[7];
945 void DISK::set_data_crc_error(bool value)
948 uint8_t *t = sector - 0x10;
949 t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]);
951 data_crc_error = value;
954 void DISK::set_data_mark_missing()
957 uint8_t *t = sector - 0x10;
958 t[8] = (t[8] & 0x0f) | 0xf0;
962 //addr_crc_error = false;
963 data_crc_error = false;
966 bool DISK::format_track(int trk, int side)
968 // disk not inserted or invalid media type
969 if(!(inserted && check_media_type())) {
974 int trkside = is_1dd_image ? trk : (trk * 2 + (side & 1));
975 if(!(0 <= trkside && trkside < 164)) {
979 // create new empty track
982 trim_required = false;
984 memset(buffer + DISK_BUFFER_SIZE, 0, sizeof(buffer) - DISK_BUFFER_SIZE);
986 offset.d = DISK_BUFFER_SIZE;
987 offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4);
989 trim_required = true;
991 track_mfm = drive_mfm;
996 void DISK::insert_sector(uint8_t c, uint8_t h, uint8_t r, uint8_t n, bool deleted, bool data_crc_error, uint8_t fill_data, int length)
998 uint8_t* t = buffer + DISK_BUFFER_SIZE;
1001 for(int i = 0; i < (sector_num.sd - 1); i++) {
1002 t[4] = sector_num.b.l;
1003 t[5] = sector_num.b.h;
1005 data_size.read_2bytes_le_from(t + 14);
1006 t += data_size.sd + 0x10;
1012 t[4] = sector_num.b.l;
1013 t[5] = sector_num.b.h;
1014 t[6] = track_mfm ? 0 : 0x40;
1015 t[7] = deleted ? 0x10 : 0;
1016 t[8] = data_crc_error ? 0xb0 : t[7];
1017 t[14] = (length >> 0) & 0xff;
1018 t[15] = (length >> 8) & 0xff;
1019 memset(t + 16, fill_data, length);
1024 void DISK::sync_buffer()
1028 trim_required = false;
1032 void DISK::trim_buffer()
1034 int max_tracks = 164;
1035 uint32_t dest_offset = 0x2b0;
1038 memset(tmp_buffer, 0, sizeof(tmp_buffer));
1039 memcpy(tmp_buffer, buffer, 0x20);
1042 for(int trkside = 0; trkside < 164; trkside++) {
1043 pair_t src_trk_offset;
1044 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1045 if(src_trk_offset.d != 0) {
1047 if(src_trk_offset.d < 0x2b0) {
1048 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1051 if(src_trk_offset.d != 0x2b0) {
1052 max_tracks = (src_trk_offset.d - 0x20) >> 2;
1053 if(max_tracks > 164) {
1054 dest_offset = 0x20 + max_tracks * 4);
1063 for(int trkside = 0; trkside < max_tracks; trkside++) {
1064 pair_t src_trk_offset;
1065 src_trk_offset.read_4bytes_le_from(buffer + 0x20 + trkside * 4);
1067 pair_t dest_trk_offset;
1068 dest_trk_offset.d = 0;
1070 if(IS_VALID_TRACK(src_trk_offset.d)) {
1071 uint8_t* t = buffer + src_trk_offset.d;
1072 pair_t sector_num, data_size;
1073 sector_num.read_2bytes_le_from(t + 4);
1074 if(sector_num.sd != 0) {
1075 dest_trk_offset.d = dest_offset;
1076 for(int i = 0; i < sector_num.sd; i++) {
1077 data_size.read_2bytes_le_from(t + 14);
1078 memcpy(tmp_buffer + dest_offset, t, data_size.sd + 0x10);
1079 dest_offset += data_size.sd + 0x10;
1080 t += data_size.sd + 0x10;
1084 dest_trk_offset.write_4bytes_le_to(tmp_buffer + 0x20 + trkside * 4);
1088 file_size.d = dest_offset;
1089 file_size.write_4bytes_le_to(tmp_buffer + 0x1c);
1091 memset(buffer, 0, sizeof(buffer));
1092 memcpy(buffer, tmp_buffer, min(sizeof(buffer), file_size.d));
1097 if(drive_rpm != 0) {
1099 } else if(inserted) {
1100 return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
1102 return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
1106 int DISK::get_track_size()
1109 return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100;
1111 return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
1115 double DISK::get_usec_per_track()
1117 return 1000000.0 / (get_rpm() / 60.0);
1120 double DISK::get_usec_per_bytes(int bytes)
1122 return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
1125 int DISK::get_bytes_per_usec(double usec)
1127 return (int)(usec / get_usec_per_bytes(1) + 0.5);
1130 bool DISK::check_media_type()
1132 switch(drive_type) {
1134 #if defined(_FM77AV40) || defined(_FM77AV40EX) || defined(_FM77AV40SX) || \
1135 defined(_FM77AV20) || defined(_FM77AV20EX)
1136 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1138 return (media_type == MEDIA_TYPE_2D);
1140 case DRIVE_TYPE_2DD:
1141 return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
1142 case DRIVE_TYPE_2HD:
1143 return (media_type == MEDIA_TYPE_2HD);
1144 case DRIVE_TYPE_144:
1145 return (media_type == MEDIA_TYPE_144);
1146 case DRIVE_TYPE_UNK:
1147 return true; // always okay
1154 #define COPYBUFFER(src, size) { \
1155 if(file_size.d + (size) > DISK_BUFFER_SIZE) { \
1158 memcpy(buffer + file_size.d, (src), (size)); \
1159 file_size.d += (size); \
1168 uint32_t trkptr[164];
1174 uint8_t dens, del, stat;
1179 // teledisk image decoder
1182 this teledisk image decoder is based on:
1184 LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
1185 LZSS coded by Haruhiko OKUMURA
1186 Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
1187 Edited and translated to English by Kenji RIKITAKE
1191 #define STRING_BUFFER_SIZE 4096
1192 #define LOOKAHEAD_BUFFER_SIZE 60
1194 #define N_CHAR (256 - THRESHOLD + LOOKAHEAD_BUFFER_SIZE)
1195 #define TABLE_SIZE (N_CHAR * 2 - 1)
1196 #define ROOT_POSITION (TABLE_SIZE - 1)
1197 #define MAX_FREQ 0x8000
1199 static uint8_t td_text_buf[STRING_BUFFER_SIZE + LOOKAHEAD_BUFFER_SIZE - 1];
1200 static uint16_t td_ptr;
1201 static uint16_t td_bufcnt, td_bufndx, td_bufpos;
1202 static uint16_t td_ibufcnt, td_ibufndx;
1203 static uint8_t td_inbuf[512];
1204 static uint16_t td_freq[TABLE_SIZE + 1];
1205 static short td_prnt[TABLE_SIZE + N_CHAR];
1206 static short td_son[TABLE_SIZE];
1207 static uint16_t td_getbuf;
1208 static uint8_t td_getlen;
1210 static const uint8_t td_d_code[256] = {
1211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1213 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1214 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
1215 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1216 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1217 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1218 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
1219 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
1220 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
1221 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
1222 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
1223 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
1224 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
1225 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
1226 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
1228 static const uint8_t td_d_len[256] = {
1229 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1230 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
1231 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1232 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1233 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
1234 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1235 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1236 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1237 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
1238 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1239 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1240 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
1241 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1242 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1243 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
1244 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
1247 static int td_next_word(FILEIO* fio)
1249 if(td_ibufndx >= td_ibufcnt) {
1250 td_ibufndx = td_ibufcnt = 0;
1251 memset(td_inbuf, 0, 512);
1252 for(int i = 0; i < 512; i++) {
1253 int d = fio->Fgetc();
1264 while(td_getlen <= 8) {
1265 td_getbuf |= td_inbuf[td_ibufndx++] << (8 - td_getlen);
1271 static int td_get_bit(FILEIO* fio)
1273 if(td_next_word(fio) < 0) {
1276 short i = td_getbuf;
1279 return (i < 0) ? 1 : 0;
1282 static int td_get_byte(FILEIO* fio)
1284 if(td_next_word(fio) != 0) {
1287 uint16_t i = td_getbuf;
1294 static void td_start_huff()
1297 for(i = 0; i < N_CHAR; i++) {
1299 td_son[i] = i + TABLE_SIZE;
1300 td_prnt[i + TABLE_SIZE] = i;
1303 while(j <= ROOT_POSITION) {
1304 td_freq[j] = td_freq[i] + td_freq[i + 1];
1306 td_prnt[i] = td_prnt[i + 1] = j;
1309 td_freq[TABLE_SIZE] = 0xffff;
1310 td_prnt[ROOT_POSITION] = 0;
1313 static void td_reconst()
1317 for(i = 0; i < TABLE_SIZE; i++) {
1318 if(td_son[i] >= TABLE_SIZE) {
1319 td_freq[j] = (td_freq[i] + 1) / 2;
1320 td_son[j] = td_son[i];
1324 for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
1326 f = td_freq[j] = td_freq[i] + td_freq[k];
1327 for(k = j - 1; f < td_freq[k]; k--);
1330 memmove(&td_freq[k + 1], &td_freq[k], l);
1332 memmove(&td_son[k + 1], &td_son[k], l);
1335 for(i = 0; i < TABLE_SIZE; i++) {
1336 if((k = td_son[i]) >= TABLE_SIZE) {
1339 td_prnt[k] = td_prnt[k + 1] = i;
1344 static void td_update(int c)
1347 if(td_freq[ROOT_POSITION] == MAX_FREQ) {
1350 c = td_prnt[c + TABLE_SIZE];
1353 if(k > td_freq[l = c + 1]) {
1354 while(k > td_freq[++l]);
1356 td_freq[c] = td_freq[l];
1360 if(i < TABLE_SIZE) {
1366 if(j < TABLE_SIZE) {
1373 while((c = td_prnt[c]) != 0);
1376 static short td_decode_char(FILEIO* fio)
1379 uint16_t c = td_son[ROOT_POSITION];
1380 while(c < TABLE_SIZE) {
1381 if((ret = td_get_bit(fio)) < 0) {
1392 static short td_decode_position(FILEIO* fio)
1396 if((bit = td_get_byte(fio)) < 0) {
1400 c = (uint16_t)td_d_code[i] << 6;
1401 j = td_d_len[i] - 2;
1403 if((bit = td_get_bit(fio)) < 0) {
1408 return (c | i & 0x3f);
1411 static void td_init_decode()
1413 td_ibufcnt= td_ibufndx = td_bufcnt = td_getbuf = 0;
1416 for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
1417 td_text_buf[i] = ' ';
1419 td_ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
1422 static int td_decode(FILEIO* fio, uint8_t *buf, int len)
1426 for(count = 0; count < len;) {
1427 if(td_bufcnt == 0) {
1428 if((c = td_decode_char(fio)) < 0) {
1432 *(buf++) = (uint8_t)c;
1433 td_text_buf[td_ptr++] = (uint8_t)c;
1434 td_ptr &= (STRING_BUFFER_SIZE - 1);
1437 if((pos = td_decode_position(fio)) < 0) {
1440 td_bufpos = (td_ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
1441 td_bufcnt = c - 255 + THRESHOLD;
1445 while(td_bufndx < td_bufcnt && count < len) {
1446 c = td_text_buf[(td_bufpos + td_bufndx) & (STRING_BUFFER_SIZE - 1)];
1447 *(buf++) = (uint8_t)c;
1449 td_text_buf[td_ptr++] = (uint8_t)c;
1450 td_ptr &= (STRING_BUFFER_SIZE - 1);
1453 if(td_bufndx >= td_bufcnt) {
1454 td_bufndx = td_bufcnt = 0;
1481 uint8_t nsec, trk, head;
1490 bool DISK::teledisk_to_d88(FILEIO *fio)
1497 bool temporary = false;
1499 // check teledisk header
1500 fio->Fseek(0, FILEIO_SEEK_SET);
1501 fio->Fread(&hdr, sizeof(td_hdr_t), 1);
1502 if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
1503 // this image is compressed
1504 // decompress to the temporary file
1505 FILEIO* fio_tmp = new FILEIO();
1506 if(!fio_tmp->Fopen(local_path(_T("teledisk.$$$")), FILEIO_WRITE_BINARY)) {
1513 if((rd = td_decode(fio, obuf, 512)) > 0) {
1514 fio_tmp->Fwrite(obuf, rd, 1);
1522 // reopen the temporary file
1524 if(!fio->Fopen(_T("teledisk.$$$"), FILEIO_READ_BINARY)) {
1527 } else if(hdr.sig[0] == 'T' && hdr.sig[1] == 'D') {
1528 // this image is not compressed
1532 if(hdr.flag & 0x80) {
1534 fio->Fread(&cmt, sizeof(td_cmt_t), 1);
1535 fio->Fseek(cmt.len, FILEIO_SEEK_CUR);
1538 // create d88 header
1542 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1543 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
1544 d88_hdr.protect = 0; // non-protected
1547 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1550 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1551 fio->Fread(&trk, sizeof(td_trk_t), 1);
1552 while(trk.nsec != 0xff) {
1553 d88_hdr.trkptr[trkcnt++] = trkptr;
1554 if(hdr.sides == 1) {
1558 // read sectors in this track
1559 for(int i = 0; i < trk.nsec; i++) {
1560 uint8_t buf[2048], dst[2048];
1561 memset(buf, 0, sizeof(buf));
1562 memset(dst, 0, sizeof(dst));
1564 // read sector header
1565 fio->Fread(&sct, sizeof(td_sct_t), 1);
1567 // create d88 sector header
1568 memset(&d88_sct, 0, sizeof(d88_sct_t));
1573 d88_sct.nsec = trk.nsec;
1574 d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
1575 d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
1576 d88_sct.stat = (sct.ctrl & 2) ? 0xb0 : d88_sct.del;
1577 d88_sct.size = secsize[sct.n & 3];
1579 // create sector image
1580 if(sct.ctrl & 0x30) {
1581 d88_sct.stat = 0xf0; // data mark missing
1584 // read sector source
1585 int len = fio->Fgetc();
1586 len += fio->Fgetc() * 256 - 1;
1587 int flag = fio->Fgetc(), d = 0;
1588 fio->Fread(buf, len, 1);
1592 memcpy(dst, buf, len);
1593 } else if(flag == 1) {
1595 len2.read_2bytes_le_from(buf);
1600 } else if(flag == 2) {
1601 for(int s = 0; s < len;) {
1602 int type = buf[s++];
1603 int len2 = buf[s++];
1606 dst[d++] = buf[s++];
1608 } else if(type < 5) {
1614 for(int j = 0; j < n; j++) {
1618 for(int j = 0; j < n; j++) {
1623 break; // unknown type
1627 break; // unknown flag
1632 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1633 COPYBUFFER(dst, d88_sct.size);
1634 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1637 fio->Fread(&trk, sizeof(td_trk_t), 1);
1639 d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1640 d88_hdr.size = trkptr;
1641 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1644 FILEIO::RemoveFile(_T("teledisk.$$$"));
1649 // imagedisk image decoder (from MESS formats/imd_dsk.c by Mr.Miodrag Milanovic)
1651 bool DISK::imagedisk_to_d88(FILEIO *fio)
1653 int size = fio->FileLength();
1654 fio->Fseek(0, FILEIO_SEEK_SET);
1655 fio->Fread(tmp_buffer, size, 1);
1657 if(memcmp(tmp_buffer, "IMD ", 4) != 0) {
1662 for(pos = 0; pos < size && tmp_buffer[pos] != 0x1a; pos++);
1669 // create d88 header
1673 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1674 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
1675 d88_hdr.protect = 0; // non-protected
1678 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1681 int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
1686 // check track header
1687 uint8_t mode = tmp_buffer[pos++];
1688 uint8_t track = tmp_buffer[pos++];
1689 uint8_t head = tmp_buffer[pos++];
1690 uint8_t sector_count = tmp_buffer[pos++];
1691 uint8_t ssize = tmp_buffer[pos++];
1693 if(sector_count == 0) {
1699 uint32_t actual_size = ssize < 7 ? 128 << ssize : 8192;
1702 const uint8_t *snum = &tmp_buffer[pos];
1703 pos += sector_count;
1704 const uint8_t *tnum = head & 0x80 ? &tmp_buffer[pos] : NULL;
1706 pos += sector_count;
1707 const uint8_t *hnum = head & 0x40 ? &tmp_buffer[pos] : NULL;
1709 pos += sector_count;
1713 int trkside = track * 2 + (head & 1);
1715 if(trkcnt < trkside) {
1718 d88_hdr.trkptr[trkside] = trkptr;
1720 if(img_mode == -1) {
1721 img_mode = mode & 3;
1724 // read sectors in this track
1725 for(int i = 0; i < sector_count; i++) {
1726 // create d88 sector header
1727 uint8_t stype = tmp_buffer[pos++];
1728 memset(&d88_sct, 0, sizeof(d88_sct_t));
1729 d88_sct.c = tnum ? tnum[i] : track;
1730 d88_sct.h = hnum ? hnum[i] : head;
1731 d88_sct.r = snum[i];
1733 d88_sct.nsec = sector_count;
1734 d88_sct.dens = (mode < 3) ? 0x40 : 0;
1736 if(stype == 0 || stype > 8) {
1737 d88_sct.stat = 0xf0; // data mark missing
1740 d88_sct.del = (stype == 3 || stype == 4 || stype == 7 || stype == 8) ? 0x10 : 0;
1741 d88_sct.stat = (stype == 5 || stype == 6 || stype == 7 || stype == 8) ? 0xb0 : d88_sct.del;
1742 d88_sct.size = actual_size;
1744 // create sector image
1745 if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
1746 memset(dst, tmp_buffer[pos++], actual_size);
1748 memcpy(dst, &tmp_buffer[pos], actual_size);
1749 pos += d88_sct.size;
1755 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1756 COPYBUFFER(dst, d88_sct.size);
1757 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1761 d88_hdr.type = (img_mode == 0) ? MEDIA_TYPE_2HD : (((trkcnt + 1) >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
1762 d88_hdr.size = trkptr;
1763 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1767 // cpdread image decoder (from MESS formats/dsk_dsk.c by Mr.Olivier Galibert)
1769 #define DSK_FORMAT_HEADER "MV - CPC"
1770 #define EXT_FORMAT_HEADER "EXTENDED CPC DSK"
1773 struct track_header {
1774 uint8_t headertag[13];
1777 uint8_t track_number;
1778 uint8_t side_number;
1781 uint8_t sector_size_code;
1782 uint8_t number_of_sector;
1783 uint8_t gap3_length;
1784 uint8_t filler_byte;
1786 struct sector_header {
1790 uint8_t sector_size_code;
1791 uint8_t fdc_status_reg1;
1792 uint8_t fdc_status_reg2;
1793 uint16_t data_length;
1797 bool DISK::cpdread_to_d88(FILEIO *fio)
1799 bool extendformat = false;
1800 int image_size = fio->FileLength();
1802 fio->Fseek(0, FILEIO_SEEK_SET);
1803 fio->Fread(tmp_buffer, image_size, 1);
1805 if(memcmp(tmp_buffer, EXT_FORMAT_HEADER, 16) == 0) {
1806 extendformat = true;
1807 } else if(memcmp(tmp_buffer, DSK_FORMAT_HEADER, 8) == 0) {
1808 extendformat = false;
1813 int heads = tmp_buffer[0x31];
1818 int tracks = tmp_buffer[0x30];
1819 int track_offsets[84 * 2];
1820 bool track_offsets_error = false;
1822 int cnt = 0, tmp = 0x100;
1823 for(int i = 0; i < tracks * heads; i++) {
1824 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1827 track_offsets[cnt] = tmp;
1828 tmp += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
1832 int cnt = 0, tmp = 0x100;
1833 for(int i = 0; i < tracks * heads; i++) {
1834 int length = tmp_buffer[0x34 + i] << 8;
1836 if(track_offsets_error = (memcmp(tmp_buffer + tmp, "Track-Info", 10) != 0)) {
1839 track_offsets[cnt] = tmp;
1842 track_offsets[cnt] = image_size;
1847 if(track_offsets_error) {
1848 // I found the dsk image that the track size in table is 1100h, but the actual track size is 900h,
1849 // so I modified this code to search "Track-Info" at the top of track information block
1850 int cnt = 0, tmp = 0x100;
1851 for(int i = 0; i < tracks * heads; i++) {
1853 for(; tmp < image_size; tmp += 0x10) {
1854 if(found = (memcmp(tmp_buffer + tmp, "Track-Info", 10) == 0)) {
1859 track_offsets[cnt] = tmp;
1862 track_offsets[cnt] = image_size;
1868 // create d88 header
1872 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1873 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDREAD");
1874 d88_hdr.protect = 0; // non-protected
1877 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1880 int total = 0, trkptr = sizeof(d88_hdr_t);
1882 for(int track = 0; track < tracks; track++) {
1883 for(int side = 0; side < heads; side++) {
1884 if(track_offsets[(track << 1) + side] >= image_size) {
1887 if((track << 1) + side < 164) {
1888 d88_hdr.trkptr[(track << 1) + side] = trkptr;
1892 memcpy(&tr, tmp_buffer + track_offsets[(track << 1) + side], sizeof(tr));
1893 int pos = track_offsets[(track << 1) + side] + 0x100;
1894 for(int j = 0; j < tr.number_of_sector; j++) {
1895 sector_header sector;
1896 memcpy(§or, tmp_buffer + track_offsets[(track << 1) + side] + sizeof(tr) + (sizeof(sector) * j), sizeof(sector));
1898 // create d88 sector header
1899 memset(&d88_sct, 0, sizeof(d88_sct_t));
1900 d88_sct.c = sector.track;
1901 d88_sct.h = sector.side;
1902 d88_sct.r = sector.sector_id;
1903 d88_sct.n = sector.sector_size_code;
1904 d88_sct.nsec = tr.number_of_sector;
1906 d88_sct.size = sector.data_length;
1907 d88_sct.dens = (tr.rec_mode == 1) ? 0x40 : 0;
1909 d88_sct.size = 128 << tr.sector_size_code;
1910 d88_sct.dens = (tr.sector_size_code == 0) ? 0x40 : 0; // FIXME
1912 d88_sct.del = (sector.fdc_status_reg1 == 0xb2) ? 0x10 : 0;
1913 d88_sct.stat = (d88_sct.size == 0) ? 0xf0 : (sector.fdc_status_reg1 == 0xb5) ? 0xb0 : d88_sct.del;
1916 if((track << 1) + side < 164) {
1917 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
1918 COPYBUFFER(tmp_buffer + pos, d88_sct.size);
1919 trkptr += sizeof(d88_sct_t) + d88_sct.size;
1921 total += d88_sct.size;
1924 pos += sector.data_length;
1926 pos += 128 << tr.sector_size_code;
1931 d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
1932 d88_hdr.size = trkptr;
1933 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
1937 // solid image decoder
1939 bool DISK::solid_to_d88(FILEIO *fio, int type, int ncyl, int nside, int nsec, int size, bool mfm)
1945 solid_nside = nside;
1950 // create d88 header
1954 memset(&d88_hdr, 0, sizeof(d88_hdr_t));
1955 my_strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "SOLID");
1956 d88_hdr.protect = 0; // non-protected
1959 COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
1962 for(int i = 0; i < 8; i++) {
1963 if(size == (128 << i)) {
1970 int trkptr = sizeof(d88_hdr_t);
1972 for(int c = 0; c < ncyl; c++) {
1973 for(int h = 0; h < nside; h++) {
1974 d88_hdr.trkptr[t++] = trkptr;
1979 // read sectors in this track
1980 for(int s = 0; s < nsec; s++) {
1981 // create d88 sector header
1982 memset(&d88_sct, 0, sizeof(d88_sct_t));
1987 d88_sct.nsec = nsec;
1991 d88_sct.size = size;
1993 // create sector image
1995 memset(dst, 0xe5, sizeof(dst));
1996 fio->Fread(dst, size, 1);
1999 COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
2000 COPYBUFFER(dst, size);
2001 trkptr += sizeof(d88_sct_t) + size;
2005 d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
2006 d88_hdr.size = trkptr;
2007 memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
2011 #define STATE_VERSION 12
2013 void DISK::save_state(FILEIO* state_fio)
2015 state_fio->FputUint32(STATE_VERSION);
2017 state_fio->Fwrite(buffer, sizeof(buffer), 1);
2018 state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
2019 state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
2020 state_fio->FputUint32(file_size.d);
2021 state_fio->FputInt32(file_bank);
2022 state_fio->FputUint32(crc32);
2023 state_fio->FputBool(trim_required);
2024 state_fio->FputBool(is_1dd_image);
2025 state_fio->FputBool(is_solid_image);
2026 state_fio->FputBool(is_fdi_image);
2027 state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
2028 state_fio->FputInt32(solid_ncyl);
2029 state_fio->FputInt32(solid_nside);
2030 state_fio->FputInt32(solid_nsec);
2031 state_fio->FputInt32(solid_size);
2032 state_fio->FputBool(solid_mfm);
2033 state_fio->FputBool(inserted);
2034 state_fio->FputBool(ejected);
2035 state_fio->FputBool(write_protected);
2036 state_fio->FputBool(changed);
2037 state_fio->FputUint8(media_type);
2038 state_fio->FputInt32(is_special_disk);
2039 state_fio->Fwrite(track, sizeof(track), 1);
2040 state_fio->FputInt32(sector_num.sd);
2041 state_fio->FputBool(track_mfm);
2042 state_fio->FputBool(invalid_format);
2043 //state_fio->FputBool(no_skew);
2044 state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
2045 state_fio->Fwrite(am1_position, sizeof(am1_position), 1);
2046 state_fio->Fwrite(id_position, sizeof(id_position), 1);
2047 state_fio->Fwrite(data_position, sizeof(data_position), 1);
2048 // state_fio->FputInt32(gap3_size);
2049 state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
2050 state_fio->FputInt32(sector_size.sd);
2051 state_fio->Fwrite(id, sizeof(id), 1);
2052 state_fio->FputUint8(density);
2053 state_fio->FputBool(deleted);
2054 state_fio->FputBool(addr_crc_error);
2055 state_fio->FputBool(data_crc_error);
2056 state_fio->FputUint8(drive_type);
2057 state_fio->FputInt32(drive_rpm);
2058 state_fio->FputBool(drive_mfm);
2061 bool DISK::load_state(FILEIO* state_fio)
2063 if(state_fio->FgetUint32() != STATE_VERSION) {
2066 state_fio->Fread(buffer, sizeof(buffer), 1);
2067 state_fio->Fread(orig_path, sizeof(orig_path), 1);
2068 state_fio->Fread(dest_path, sizeof(dest_path), 1);
2069 file_size.d = state_fio->FgetUint32();
2070 file_bank = state_fio->FgetInt32();
2071 crc32 = state_fio->FgetUint32();
2072 trim_required = state_fio->FgetBool();
2073 is_1dd_image = state_fio->FgetBool();
2074 is_solid_image = state_fio->FgetBool();
2075 is_fdi_image = state_fio->FgetBool();
2076 state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
2077 solid_ncyl = state_fio->FgetInt32();
2078 solid_nside = state_fio->FgetInt32();
2079 solid_nsec = state_fio->FgetInt32();
2080 solid_size = state_fio->FgetInt32();
2081 solid_mfm = state_fio->FgetBool();
2082 inserted = state_fio->FgetBool();
2083 ejected = state_fio->FgetBool();
2084 write_protected = state_fio->FgetBool();
2085 changed = state_fio->FgetBool();
2086 media_type = state_fio->FgetUint8();
2087 is_special_disk = state_fio->FgetInt32();
2088 state_fio->Fread(track, sizeof(track), 1);
2089 sector_num.sd = state_fio->FgetInt32();
2090 track_mfm = state_fio->FgetBool();
2091 invalid_format = state_fio->FgetBool();
2092 //no_skew = state_fio->FgetBool();
2093 state_fio->Fread(sync_position, sizeof(sync_position), 1);
2094 state_fio->Fread(am1_position, sizeof(am1_position), 1);
2095 state_fio->Fread(id_position, sizeof(id_position), 1);
2096 state_fio->Fread(data_position, sizeof(data_position), 1);
2097 // gap3_size = state_fio->FgetInt32();
2098 int offset = state_fio->FgetInt32();
2099 sector = (offset != -1) ? buffer + offset : NULL;
2100 sector_size.sd = state_fio->FgetInt32();
2101 state_fio->Fread(id, sizeof(id), 1);
2102 density = state_fio->FgetUint8();
2103 deleted = state_fio->FgetBool();
2104 addr_crc_error = state_fio->FgetBool();
2105 data_crc_error = state_fio->FgetBool();
2106 drive_type = state_fio->FgetUint8();
2107 drive_rpm = state_fio->FgetInt32();
2108 drive_mfm = state_fio->FgetBool();