-/*\r
- Skelton for retropc emulator\r
-\r
- Author : Takeda.Toshiya\r
- Date : 2006.09.16-\r
-\r
- [ d88 handler ]\r
-*/\r
-\r
-#include "disk.h"\r
-#include "../fileio.h"\r
-#if defined(_USE_AGAR) || defined(_USE_SDL)\r
-#include "agar_logger.h"\r
-#endif\r
-\r
-// crc table\r
-static const uint16 crc_table[256] = {\r
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,\r
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,\r
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,\r
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,\r
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,\r
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,\r
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,\r
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,\r
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,\r
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,\r
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,\r
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,\r
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,\r
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,\r
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,\r
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0\r
-};\r
-\r
-// teledisk decoder table\r
-static const uint8 d_code[256] = {\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\r
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,\r
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,\r
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\r
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\r
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\r
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,\r
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,\r
- 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,\r
- 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,\r
- 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,\r
- 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,\r
- 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,\r
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f\r
-};\r
-static const uint8 d_len[256] = {\r
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,\r
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,\r
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,\r
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,\r
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,\r
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\r
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\r
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\r
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\r
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,\r
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,\r
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,\r
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\r
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\r
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,\r
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08\r
-};\r
-static const int secsize[8] = {\r
- 128, 256, 512, 1024, 2048, 4096, 8192, 16384\r
-};\r
-\r
-static uint8 tmp_buffer[DISK_BUFFER_SIZE];\r
-\r
-DISK::DISK()\r
-{\r
- inserted = ejected = write_protected = changed = false;\r
- file_size = 0;\r
- sector_size = sector_num = 0;\r
- sector = NULL;\r
- drive_type = DRIVE_TYPE_UNK;\r
- drive_rpm = 0;\r
- drive_mfm = true;\r
-}\r
-\r
-DISK::~DISK()\r
-{\r
- if(inserted) {\r
- close();\r
- }\r
-}\r
-\r
-typedef struct fd_format {\r
- int type;\r
- int ncyl, nside, nsec, size;\r
-} fd_format;\r
-\r
-static const fd_format fd_formats[] = {\r
- { MEDIA_TYPE_2D, 40, 1, 16, 256 }, // 1D 160KB\r
- { MEDIA_TYPE_2D , 40, 2, 16, 256 }, // 2D 320KB\r
-#ifdef _MZ2500\r
- { MEDIA_TYPE_2DD, 80, 2, 16, 256 }, // 2DD 640KB (MZ-2500)\r
-#else\r
- { MEDIA_TYPE_2DD, 80, 2, 8, 512 }, // 2DD 640KB\r
-#endif\r
- { MEDIA_TYPE_2DD, 80, 2, 9, 512 }, // 2DD 720KB\r
- { MEDIA_TYPE_2HD, 80, 2, 15, 512 }, // 2HC 1.20MB\r
- { MEDIA_TYPE_2HD, 77, 2, 8, 1024 }, // 2HD 1.25MB\r
- { MEDIA_TYPE_144, 80, 2, 18, 512 }, // 2HD 1.44MB\r
- { MEDIA_TYPE_144, 80, 2, 36, 512 }, // 2ED 2.88MB\r
- { -1, 0, 0, 0, 0 },\r
-};\r
-\r
-void DISK::open(_TCHAR path[], int offset)\r
-{\r
- // check current disk image\r
- if(inserted) {\r
-#if defined(_USE_AGAR) || defined(_USE_SDL)\r
- AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);\r
-#endif\r
- if(_tcsicmp(orig_path, path) == 0 && file_offset == offset) {\r
- return;\r
- }\r
- close();\r
- }\r
- memset(buffer, 0, sizeof(buffer));\r
- media_type = MEDIA_TYPE_UNK;\r
- is_standard_image = is_fdi_image = false;\r
-#if defined(_USE_AGAR) || defined(_USE_SDL)\r
- AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);\r
-#endif \r
- // open disk image\r
- fi = new FILEIO();\r
- if(fi->Fopen(path, FILEIO_READ_BINARY)) {\r
- bool converted = false;\r
- \r
- _tcscpy(orig_path, path);\r
- _tcscpy(dest_path, path);\r
- _stprintf(temp_path, _T("%s.$$$"), path);\r
- temporary = false;\r
- \r
- // check if file protected\r
- write_protected = fi->IsProtected(path);\r
- \r
- // is this d88 format ?\r
- if(check_file_extension(path, _T(".d88")) || check_file_extension(path, _T(".d77")) ||\r
- check_file_extension(path, _T(".D88")) || check_file_extension(path, _T(".D77"))) {\r
- fi->Fseek(offset + 0x1c, FILEIO_SEEK_SET);\r
- file_size = fi->Fgetc();\r
- file_size |= fi->Fgetc() << 8;\r
- file_size |= fi->Fgetc() << 16;\r
- file_size |= fi->Fgetc() << 24;\r
- fi->Fseek(offset, FILEIO_SEEK_SET);\r
- fi->Fread(buffer, file_size, 1);\r
- file_offset = offset;\r
- inserted = changed = true;\r
- goto file_loaded;\r
- }\r
- \r
- fi->Fseek(0, FILEIO_SEEK_END);\r
- file_size = fi->Ftell();\r
- fi->Fseek(0, FILEIO_SEEK_SET);\r
- file_offset = 0;\r
- \r
-#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)\r
- // is this 2d format ?\r
- if(check_file_extension(path, _T(".2d"))) {\r
- if(standard_to_d88(MEDIA_TYPE_2D, 40, 2, 16, 256)) {\r
- inserted = changed = is_standard_image = true;\r
- goto file_loaded;\r
- }\r
- fi->Fseek(0, FILEIO_SEEK_SET);\r
- }\r
-#endif\r
- \r
- // check image file format\r
- for(int i = 0;; i++) {\r
- const fd_format *p = &fd_formats[i];\r
- if(p->type == -1) {\r
- break;\r
- }\r
- int len = p->ncyl * p->nside * p->nsec * p->size;\r
- // 4096 bytes: FDI header ???\r
- if(file_size == len || (file_size == (len + 4096) && (len == 655360 || len == 1261568))) {\r
- if(file_size == len + 4096) {\r
- is_fdi_image = true;\r
- fi->Fread(fdi_header, 4096, 1);\r
- }\r
- if(standard_to_d88(p->type, p->ncyl, p->nside, p->nsec, p->size)) {\r
- inserted = changed = is_standard_image = true;\r
- goto file_loaded;\r
- }\r
- }\r
- }\r
- if(0 < file_size && file_size <= DISK_BUFFER_SIZE) {\r
- memset(buffer, 0, sizeof(buffer));\r
- fi->Fread(buffer, file_size, 1);\r
- \r
- // check d88 format (temporary)\r
- if(*(uint32 *)(buffer + 0x1c) == file_size) {\r
- inserted = changed = true;\r
- goto file_loaded;\r
- }\r
- _stprintf(dest_path, _T("%s.D88"), path);\r
- \r
- // check file header\r
- try {\r
- if(memcmp(buffer, "TD", 2) == 0 || memcmp(buffer, "td", 2) == 0) {\r
- // teledisk image file\r
- inserted = changed = converted = teledisk_to_d88();\r
- } else if(memcmp(buffer, "IMD", 3) == 0) {\r
- // imagedisk image file\r
- inserted = changed = converted = imagedisk_to_d88();\r
- } else if(memcmp(buffer, "MV - CPC", 8) == 0) {\r
- // standard cpdread image file\r
- inserted = changed = converted = cpdread_to_d88(0);\r
- } else if(memcmp(buffer, "EXTENDED", 8) == 0) {\r
- // extended cpdread image file\r
- inserted = changed = converted = cpdread_to_d88(1);\r
- }\r
- }\r
- catch(...) {\r
- // failed to convert the disk image\r
-#if defined(_USE_AGAR) || defined(_USE_SDL)\r
- AGAR_DebugLog(AGAR_LOG_INFO, "EE: disk.cpp : Failed to convert disk image.");\r
-#endif\r
- }\r
- }\r
-file_loaded:\r
- if(fi->IsOpened()) {\r
- fi->Fclose();\r
- }\r
- if(temporary) {\r
- fi->Remove(temp_path);\r
- }\r
- if(inserted) {\r
-#if 0\r
- if(converted) {\r
- // write image\r
- FILEIO* fio = new FILEIO();\r
- if(fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {\r
- fio->Fwrite(buffer, file_size, 1);\r
- fio->Fclose();\r
- }\r
- delete fio;\r
- }\r
-#endif\r
- crc32 = getcrc32(buffer, file_size);\r
- }\r
- if(buffer[0x1a] != 0) {\r
- write_protected = true;\r
- }\r
- if(media_type == MEDIA_TYPE_UNK) {\r
- if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {\r
- for(int trkside = 0; trkside < 164; trkside++) {\r
- uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
- offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
- offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
- offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
- \r
- if(!offset) {\r
- continue;\r
- }\r
- // track found\r
- uint8 *t = buffer + offset;\r
- int sector_num = t[4] | (t[5] << 8);\r
- int data_size = t[14] | (t[15] << 8);\r
- \r
- if(sector_num >= 18 && data_size == 512) {\r
- media_type = MEDIA_TYPE_144;\r
- }\r
- break;\r
- }\r
- }\r
- }\r
- // FIXME: ugly patch for X1turbo ALPHA and ARCUS\r
- is_alpha = false;\r
-#if defined(_X1TURBO) || defined(_X1TURBOZ)\r
- if(media_type == MEDIA_TYPE_2D) {\r
- uint32 offset = buffer[0x20] | (buffer[0x21] << 8) | (buffer[0x22] << 16) | (buffer[0x23] << 24);\r
- uint8 *t = buffer + offset;\r
- is_alpha = (strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0);\r
- }\r
-#endif\r
- }\r
- delete fi;\r
-}\r
-\r
-void DISK::close()\r
-{\r
- // write disk image\r
- if(inserted) {\r
- if(!write_protected && file_size && getcrc32(buffer, file_size) != crc32) {\r
- // write image\r
- FILEIO* fio = new FILEIO();\r
- if(fio->Fopen(dest_path, FILEIO_READ_WRITE_BINARY)) {\r
- fio->Fseek(file_offset, FILEIO_SEEK_SET);\r
- } else {\r
- fio->Fopen(dest_path, FILEIO_WRITE_BINARY);\r
- }\r
- if(fio->IsOpened()) {\r
- if(is_standard_image) {\r
- if(is_fdi_image) {\r
- fio->Fwrite(fdi_header, 4096, 1);\r
- }\r
- for(int trkside = 0; trkside < 164; trkside++) {\r
- uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
- offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
- offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
- offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
- \r
- if(!offset) {\r
- break;\r
- }\r
- uint8* t = buffer + offset;\r
- int sector_num = t[4] | (t[5] << 8);\r
- \r
- for(int i = 0; i < sector_num; i++) {\r
- int data_size = t[14] | (t[15] << 8);\r
- fio->Fwrite(t + 0x10, data_size, 1);\r
- t += data_size + 0x10;\r
- }\r
- }\r
- } else {\r
- fio->Fwrite(buffer, file_size, 1);\r
- }\r
- fio->Fclose();\r
- }\r
- delete fio;\r
- }\r
- ejected = true;\r
- }\r
- inserted = write_protected = false;\r
- file_size = 0;\r
- sector_size = sector_num = 0;\r
- sector = NULL;\r
-}\r
-\r
-bool DISK::get_track(int trk, int side)\r
-{\r
- sector_size = sector_num = 0;\r
- no_skew = true;\r
- \r
- // disk not inserted or invalid media type\r
- if(!(inserted && check_media_type())) {\r
- return false;\r
- }\r
- \r
- // search track\r
- int trkside = trk * 2 + (side & 1);\r
- if(!(0 <= trkside && trkside < 164)) {\r
- return false;\r
- }\r
- uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
- offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
- offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
- offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
- \r
- if(!offset) {\r
- return false;\r
- }\r
- \r
- // track found\r
- sector = buffer + offset;\r
- sector_num = sector[4] | (sector[5] << 8);\r
- \r
- // create each sector position in track\r
- int sync_size = drive_mfm ? 12 : 6;\r
- int am_size = drive_mfm ? 3 : 0;\r
- int gap2_size = drive_mfm ? 22 : 11;\r
- \r
- data_size_shift = 0;\r
- too_many_sectors = false;\r
-retry:\r
- uint8* t = sector;\r
- int total = 0, gap3_size;\r
- \r
- for(int i = 0; i < sector_num; i++) {\r
- int data_size = t[14] | (t[15] << 8);\r
- \r
- if((data_size >> data_size_shift) < 0x80) {\r
- too_many_sectors = true;\r
- break;\r
- }\r
- total += sync_size + (am_size + 1) + (4 + 2) + gap2_size + sync_size + (am_size + 1);\r
- total += (data_size >> data_size_shift) + 2;\r
- \r
- t += data_size + 0x10;\r
- }\r
- if(too_many_sectors) {\r
- // Too many sectors in this track\r
- gap3_size = 32;\r
- data_size_shift = 0;\r
- } else if((gap3_size = (get_track_size() - total) / (sector_num + 2)) < 12) {\r
- // ID:N is modified\r
- data_size_shift++;\r
- goto retry;\r
- }\r
- t = sector;\r
- total = gap3_size * 2;\r
- \r
- for(int i = 0; i < sector_num; i++) {\r
- int data_size = t[14] | (t[15] << 8);\r
- \r
- if(too_many_sectors) {\r
- total = gap3_size * 2 + (get_track_size() - gap3_size * 2) * i / sector_num;\r
- }\r
- sync_position[i] = total;\r
- total += sync_size + (am_size + 1);\r
- id_position[i] = total;\r
- total += (4 + 2) + gap2_size + sync_size + (am_size + 1);\r
- data_position[i] = total;\r
- total += (data_size >> data_size_shift) + 2 + gap3_size;\r
- \r
- if(t[2] != i + 1) {\r
- no_skew = false;\r
- }\r
- t += data_size + 0x10;\r
- }\r
- return true;\r
-}\r
-\r
-bool DISK::make_track(int trk, int side)\r
-{\r
- int track_size = get_track_size();\r
- \r
- if(!get_track(trk, side)) {\r
- // create a dummy track\r
- for(int i = 0; i < track_size; i++) {\r
- track[i] = rand();\r
- }\r
- return false;\r
- }\r
- \r
- // make track image\r
- int sync_size = drive_mfm ? 12 : 6;\r
- int am_size = drive_mfm ? 3 : 0;\r
- int gap2_size = drive_mfm ? 22 : 11;\r
- uint8 gap_data = drive_mfm ? 0x4e : 0xff;\r
- \r
- // preamble\r
- memset(track, gap_data, track_size);\r
- \r
- if(sync_position[0] >= (sync_size + am_size + 1) + (8 + 5)) {\r
- int p = (sync_position[0] - (sync_size + am_size + 1)) * 8 / (8 + 5);\r
- \r
- // sync\r
- for(int i = 0; i < sync_size; i++) {\r
- track[p++] = 0x00;\r
- }\r
- // index mark\r
- for(int i = 0; i < am_size; i++) {\r
- track[p++] = 0xc2;\r
- }\r
- track[p++] = 0xfc;\r
- }\r
- \r
- // sectors\r
- uint8 *t = sector;\r
- \r
- for(int i = 0; i < sector_num; i++) {\r
- int data_size = t[14] | (t[15] << 8);\r
- int p = sync_position[i];\r
- \r
- // sync\r
- for(int j = 0; j < sync_size; j++) {\r
- if(p < track_size) track[p++] = 0x00;\r
- }\r
- // am1\r
- for(int j = 0; j < am_size; j++) {\r
- if(p < track_size) track[p++] = 0xa1;\r
- }\r
- if(p < track_size) track[p++] = 0xfe;\r
- // id\r
- if(p < track_size) track[p++] = t[0];\r
- if(p < track_size) track[p++] = t[1];\r
- if(p < track_size) track[p++] = t[2];\r
- if(p < track_size) track[p++] = t[3];\r
- uint16 crc = 0;\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);\r
- if(p < track_size) track[p++] = crc >> 8;\r
- if(p < track_size) track[p++] = crc & 0xff;\r
- // gap2\r
- for(int j = 0; j < gap2_size; j++) {\r
- if(p < track_size) track[p++] = gap_data;\r
- }\r
- // sync\r
- for(int j = 0; j < sync_size; j++) {\r
- if(p < track_size) track[p++] = 0x00;\r
- }\r
- // am2\r
- for(int j = 0; j < am_size; j++) {\r
- if(p < track_size) track[p++] = 0xa1;\r
- }\r
- if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;\r
- // data\r
- crc = 0;\r
- for(int j = 0; j < (data_size >> data_size_shift); j++) {\r
- if(p < track_size) track[p++] = t[0x10 + j];\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);\r
- }\r
- if(p < track_size) track[p++] = crc >> 8;\r
- if(p < track_size) track[p++] = crc & 0xff;\r
- \r
- t += data_size + 0x10;\r
- }\r
- return true;\r
-}\r
-\r
-bool DISK::get_sector(int trk, int side, int index)\r
-{\r
- sector_size = sector_num = 0;\r
- sector = NULL;\r
- \r
- // disk not inserted or invalid media type\r
- if(!(inserted && check_media_type())) {\r
- return false;\r
- }\r
- \r
- // search track\r
- int trkside = trk * 2 + (side & 1);\r
- if(!(0 <= trkside && trkside < 164)) {\r
- return false;\r
- }\r
- uint32 offset = buffer[0x20 + trkside * 4 + 0];\r
- offset |= buffer[0x20 + trkside * 4 + 1] << 8;\r
- offset |= buffer[0x20 + trkside * 4 + 2] << 16;\r
- offset |= buffer[0x20 + trkside * 4 + 3] << 24;\r
- \r
- if(!offset) {\r
- return false;\r
- }\r
- \r
- // track found\r
- uint8* t = buffer + offset;\r
- sector_num = t[4] | (t[5] << 8);\r
- \r
- if(index >= sector_num) {\r
- return false;\r
- }\r
- \r
- // skip sector\r
- for(int i = 0; i < index; i++) {\r
- t += (t[14] | (t[15] << 8)) + 0x10;\r
- }\r
- \r
- // header info\r
- id[0] = t[0];\r
- id[1] = t[1];\r
- id[2] = t[2];\r
- id[3] = t[3];\r
- uint16 crc = 0;\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);\r
- crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);\r
- id[4] = crc >> 8;\r
- id[5] = crc & 0xff;\r
- density = t[6];\r
- deleted = t[7];\r
- status = t[8];\r
- sector = t + 0x10;\r
- sector_size = t[14] | (t[15] << 8);\r
- \r
- return true;\r
-}\r
-\r
-int DISK::get_rpm()\r
-{\r
- if(drive_rpm != 0) {\r
- return drive_rpm;\r
- } else if(inserted) {\r
- return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;\r
- } else {\r
- return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;\r
- }\r
-}\r
-\r
-int DISK::get_track_size()\r
-{\r
- if(inserted) {\r
- return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;\r
- } else {\r
- return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;\r
- }\r
-}\r
-\r
-double DISK::get_usec_per_bytes(int bytes)\r
-{\r
- return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;\r
-}\r
-\r
-bool DISK::check_media_type()\r
-{\r
- switch(drive_type) {\r
- case DRIVE_TYPE_2D:\r
- return (media_type == MEDIA_TYPE_2D);\r
- case DRIVE_TYPE_2DD:\r
- return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);\r
- case DRIVE_TYPE_2HD:\r
- return (media_type == MEDIA_TYPE_2HD);\r
- case DRIVE_TYPE_144:\r
- return (media_type == MEDIA_TYPE_144);\r
- case DRIVE_TYPE_UNK:\r
- return true; // always okay\r
- }\r
- return false;\r
-}\r
-\r
-// teledisk image decoder\r
-\r
-/*\r
- this teledisk image decoder is based on:\r
- \r
- LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988\r
- LZSS coded by Haruhiko OKUMURA\r
- Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI\r
- Edited and translated to English by Kenji RIKITAKE\r
- TDLZHUF.C by WTK\r
-*/\r
-\r
-#define COPYBUFFER(src, size) { \\r
- if(file_size + (size) > DISK_BUFFER_SIZE) { \\r
- return false; \\r
- } \\r
- memcpy(buffer + file_size, (src), (size)); \\r
- file_size += (size); \\r
-}\r
-\r
-bool DISK::teledisk_to_d88()\r
-{\r
- struct td_hdr_t hdr;\r
- struct td_cmt_t cmt;\r
- struct td_trk_t trk;\r
- struct td_sct_t sct;\r
- struct d88_hdr_t d88_hdr;\r
- struct d88_sct_t d88_sct;\r
- uint8 obuf[512];\r
- \r
- // check teledisk header\r
- fi->Fseek(0, FILEIO_SEEK_SET);\r
- fi->Fread(&hdr, sizeof(td_hdr_t), 1);\r
- if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {\r
- // decompress to the temporary file\r
- FILEIO* fo = new FILEIO();\r
- if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {\r
- delete fo;\r
- return false;\r
- }\r
- int rd = 1;\r
- init_decode();\r
- do {\r
- if((rd = decode(obuf, 512)) > 0) {\r
- fo->Fwrite(obuf, rd, 1);\r
- }\r
- }\r
- while(rd > 0);\r
- fo->Fclose();\r
- delete fo;\r
- temporary = true;\r
- \r
- // reopen the temporary file\r
- fi->Fclose();\r
- if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {\r
- return false;\r
- }\r
- }\r
- if(hdr.flag & 0x80) {\r
- // skip comment\r
- fi->Fread(&cmt, sizeof(td_cmt_t), 1);\r
- fi->Fseek(cmt.len, FILEIO_SEEK_CUR);\r
- }\r
- \r
- // create d88 image\r
- file_size = 0;\r
- \r
- // create d88 header\r
- memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
- strcpy(d88_hdr.title, "TELEDISK");\r
- d88_hdr.protect = 0; // non-protected\r
- COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
- \r
- // create tracks\r
- int trkcnt = 0, trkptr = sizeof(d88_hdr_t);\r
- fi->Fread(&trk, sizeof(td_trk_t), 1);\r
- while(trk.nsec != 0xff) {\r
- d88_hdr.trkptr[trkcnt++] = trkptr;\r
- if(hdr.sides == 1) {\r
- d88_hdr.trkptr[trkcnt++] = trkptr;\r
- }\r
- \r
- // read sectors in this track\r
- for(int i = 0; i < trk.nsec; i++) {\r
- uint8 buf[2048], dst[2048];\r
- memset(buf, 0, sizeof(buf));\r
- memset(dst, 0, sizeof(dst));\r
- \r
- // read sector header\r
- fi->Fread(&sct, sizeof(td_sct_t), 1);\r
- \r
- // create d88 sector header\r
- memset(&d88_sct, 0, sizeof(d88_sct_t));\r
- d88_sct.c = sct.c;\r
- d88_sct.h = sct.h;\r
- d88_sct.r = sct.r;\r
- d88_sct.n = sct.n;\r
- d88_sct.nsec = trk.nsec;\r
- d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;\r
- d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;\r
- d88_sct.stat = (sct.ctrl & 2) ? 0x10 : 0; // crc?\r
- d88_sct.size = secsize[sct.n & 3];\r
- \r
- // create sector image\r
- if(sct.ctrl != 0x10) {\r
- // read sector source\r
- int len = fi->Fgetc();\r
- len += fi->Fgetc() * 256 - 1;\r
- int flag = fi->Fgetc(), d = 0;\r
- fi->Fread(buf, len, 1);\r
- \r
- // convert\r
- if(flag == 0) {\r
- memcpy(dst, buf, len);\r
- } else if(flag == 1) {\r
- int len2 = buf[0] | (buf[1] << 8);\r
- while(len2--) {\r
- dst[d++] = buf[2];\r
- dst[d++] = buf[3];\r
- }\r
- } else if(flag == 2) {\r
- for(int s = 0; s < len;) {\r
- int type = buf[s++];\r
- int len2 = buf[s++];\r
- if(type == 0) {\r
- while(len2--) {\r
- dst[d++] = buf[s++];\r
- }\r
- } else if(type < 5) {\r
- uint8 pat[256];\r
- int n = 2;\r
- while(type-- > 1) {\r
- n *= 2;\r
- }\r
- for(int j = 0; j < n; j++) {\r
- pat[j] = buf[s++];\r
- }\r
- while(len2--) {\r
- for(int j = 0; j < n; j++) {\r
- dst[d++] = pat[j];\r
- }\r
- }\r
- } else {\r
- break; // unknown type\r
- }\r
- }\r
- } else {\r
- break; // unknown flag\r
- }\r
- } else {\r
- d88_sct.size = 0;\r
- }\r
- \r
- // copy to d88\r
- COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
- COPYBUFFER(dst, d88_sct.size);\r
- trkptr += sizeof(d88_sct_t) + d88_sct.size;\r
- }\r
- // read next track\r
- fi->Fread(&trk, sizeof(td_trk_t), 1);\r
- }\r
- d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;\r
- d88_hdr.size = trkptr;\r
- memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
- return true;\r
-}\r
-\r
-int DISK::next_word()\r
-{\r
- if(ibufndx >= ibufcnt) {\r
- ibufndx = ibufcnt = 0;\r
- memset(inbuf, 0, 512);\r
- for(int i = 0; i < 512; i++) {\r
- int d = fi->Fgetc();\r
- if(d == EOF) {\r
- if(i) {\r
- break;\r
- }\r
- return(-1);\r
- }\r
- inbuf[i] = d;\r
- ibufcnt = i + 1;\r
- }\r
- }\r
- while(getlen <= 8) {\r
- getbuf |= inbuf[ibufndx++] << (8 - getlen);\r
- getlen += 8;\r
- }\r
- return 0;\r
-}\r
-\r
-int DISK::get_bit()\r
-{\r
- if(next_word() < 0) {\r
- return -1;\r
- }\r
- short i = getbuf;\r
- getbuf <<= 1;\r
- getlen--;\r
- return (i < 0) ? 1 : 0;\r
-}\r
-\r
-int DISK::get_byte()\r
-{\r
- if(next_word() != 0) {\r
- return -1;\r
- }\r
- uint16 i = getbuf;\r
- getbuf <<= 8;\r
- getlen -= 8;\r
- i >>= 8;\r
- return (int)i;\r
-}\r
-\r
-void DISK::start_huff()\r
-{\r
- int i, j;\r
- for(i = 0; i < N_CHAR; i++) {\r
- freq[i] = 1;\r
- son[i] = i + TABLE_SIZE;\r
- prnt[i + TABLE_SIZE] = i;\r
- }\r
- i = 0; j = N_CHAR;\r
- while(j <= ROOT_POSITION) {\r
- freq[j] = freq[i] + freq[i + 1];\r
- son[j] = i;\r
- prnt[i] = prnt[i + 1] = j;\r
- i += 2; j++;\r
- }\r
- freq[TABLE_SIZE] = 0xffff;\r
- prnt[ROOT_POSITION] = 0;\r
-}\r
-\r
-void DISK::reconst()\r
-{\r
- short i, j = 0, k;\r
- uint16 f, l;\r
- for(i = 0; i < TABLE_SIZE; i++) {\r
- if(son[i] >= TABLE_SIZE) {\r
- freq[j] = (freq[i] + 1) / 2;\r
- son[j] = son[i];\r
- j++;\r
- }\r
- }\r
- for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {\r
- k = i + 1;\r
- f = freq[j] = freq[i] + freq[k];\r
- for(k = j - 1; f < freq[k]; k--);\r
- k++;\r
- l = (j - k) * 2;\r
- memmove(&freq[k + 1], &freq[k], l);\r
- freq[k] = f;\r
- memmove(&son[k + 1], &son[k], l);\r
- son[k] = i;\r
- }\r
- for(i = 0; i < TABLE_SIZE; i++) {\r
- if((k = son[i]) >= TABLE_SIZE) {\r
- prnt[k] = i;\r
- } else {\r
- prnt[k] = prnt[k + 1] = i;\r
- }\r
- }\r
-}\r
-\r
-void DISK::update(int c)\r
-{\r
- int i, j, k, l;\r
- if(freq[ROOT_POSITION] == MAX_FREQ) {\r
- reconst();\r
- }\r
- c = prnt[c + TABLE_SIZE];\r
- do {\r
- k = ++freq[c];\r
- if(k > freq[l = c + 1]) {\r
- while(k > freq[++l]);\r
- l--;\r
- freq[c] = freq[l];\r
- freq[l] = k;\r
- i = son[c];\r
- prnt[i] = l;\r
- if(i < TABLE_SIZE) {\r
- prnt[i + 1] = l;\r
- }\r
- j = son[l];\r
- son[l] = i;\r
- prnt[j] = c;\r
- if(j < TABLE_SIZE) {\r
- prnt[j + 1] = c;\r
- }\r
- son[c] = j;\r
- c = l;\r
- }\r
- }\r
- while((c = prnt[c]) != 0);\r
-}\r
-\r
-short DISK::decode_char()\r
-{\r
- int ret;\r
- uint16 c = son[ROOT_POSITION];\r
- while(c < TABLE_SIZE) {\r
- if((ret = get_bit()) < 0) {\r
- return -1;\r
- }\r
- c += (unsigned)ret;\r
- c = son[c];\r
- }\r
- c -= TABLE_SIZE;\r
- update(c);\r
- return c;\r
-}\r
-\r
-short DISK::decode_position()\r
-{\r
- short bit;\r
- uint16 i, j, c;\r
- if((bit = get_byte()) < 0) {\r
- return -1;\r
- }\r
- i = (uint16)bit;\r
- c = (uint16)d_code[i] << 6;\r
- j = d_len[i] - 2;\r
- while(j--) {\r
- if((bit = get_bit()) < 0) {\r
- return -1;\r
- }\r
- i = (i << 1) + bit;\r
- }\r
- return (c | i & 0x3f);\r
-}\r
-\r
-void DISK::init_decode()\r
-{\r
- ibufcnt= ibufndx = bufcnt = getbuf = 0;\r
- getlen = 0;\r
- start_huff();\r
- for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {\r
- text_buf[i] = ' ';\r
- }\r
- ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;\r
-}\r
-\r
-int DISK::decode(uint8 *buf, int len)\r
-{\r
- short c, pos;\r
- int count;\r
- for(count = 0; count < len;) {\r
- if(bufcnt == 0) {\r
- if((c = decode_char()) < 0) {\r
- return count;\r
- }\r
- if(c < 256) {\r
- *(buf++) = (uint8)c;\r
- text_buf[ptr++] = (uint8)c;\r
- ptr &= (STRING_BUFFER_SIZE - 1);\r
- count++;\r
- } else {\r
- if((pos = decode_position()) < 0) {\r
- return count;\r
- }\r
- bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);\r
- bufcnt = c - 255 + THRESHOLD;\r
- bufndx = 0;\r
- }\r
- } else {\r
- while(bufndx < bufcnt && count < len) {\r
- c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];\r
- *(buf++) = (uint8)c;\r
- bufndx++;\r
- text_buf[ptr++] = (uint8)c;\r
- ptr &= (STRING_BUFFER_SIZE - 1);\r
- count++;\r
- }\r
- if(bufndx >= bufcnt) {\r
- bufndx = bufcnt = 0;\r
- }\r
- }\r
- }\r
- return count;\r
-}\r
-\r
-// imagedisk image decoder\r
-\r
-bool DISK::imagedisk_to_d88()\r
-{\r
- struct imd_trk_t trk;\r
- struct d88_hdr_t d88_hdr;\r
- struct d88_sct_t d88_sct;\r
- \r
- // skip comment\r
- fi->Fseek(0, FILEIO_SEEK_SET);\r
- int tmp;\r
- while((tmp = fi->Fgetc()) != 0x1a) {\r
- if(tmp == EOF) {\r
- return false;\r
- }\r
- }\r
- \r
- // create d88 image\r
- file_size = 0;\r
- \r
- // create d88 header\r
- memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
- strcpy(d88_hdr.title, "IMAGEDISK");\r
- d88_hdr.protect = 0; // non-protected\r
- COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
- \r
- // create tracks\r
- int trkptr = sizeof(d88_hdr_t);\r
- int trkcnt = 0, mode;\r
- \r
- for(int t = 0; t < 164; t++) {\r
- // check end of file\r
- if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {\r
- break;\r
- }\r
- trkcnt = t;\r
- \r
- // check track header\r
- if(t == 0) {\r
- mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps\r
- }\r
- if(!trk.nsec) {\r
- continue;\r
- }\r
- d88_hdr.trkptr[t] = trkptr;\r
- \r
- // setup sector id\r
- uint8 c[64], h[64], r[64];\r
- fi->Fread(r, trk.nsec, 1);\r
- if(trk.head & 0x80) {\r
- fi->Fread(c, trk.nsec, 1);\r
- } else {\r
- memset(c, trk.cyl, sizeof(c));\r
- }\r
- if(trk.head & 0x40) {\r
- fi->Fread(h, trk.nsec, 1);\r
- } else {\r
- memset(h, trk.head & 1, sizeof(h));\r
- }\r
- \r
- // read sectors in this track\r
- for(int i = 0; i < trk.nsec; i++) {\r
- // create d88 sector header\r
- static const uint8 del[] = {0, 0, 0, 0x10, 0x10, 0, 0, 0x10, 0x10};\r
- static const uint8 err[] = {0, 0, 0, 0, 0, 0x10, 0x10, 0x10, 0x10};\r
- int sectype = fi->Fgetc();\r
- if(sectype > 8) {\r
- return false;\r
- }\r
- memset(&d88_sct, 0, sizeof(d88_sct_t));\r
- d88_sct.c = c[i];\r
- d88_sct.h = h[i];\r
- d88_sct.r = r[i];\r
- d88_sct.n = trk.size;\r
- d88_sct.nsec = trk.nsec;\r
- d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;\r
- d88_sct.del = del[sectype];\r
- d88_sct.stat = err[sectype];\r
- d88_sct.size = secsize[trk.size & 7];\r
- \r
- // create sector image\r
- uint8 dst[8192];\r
- if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {\r
- // uncompressed\r
- fi->Fread(dst, d88_sct.size, 1);\r
- } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {\r
- // compressed\r
- int tmp = fi->Fgetc();\r
- memset(dst, tmp, d88_sct.size);\r
- } else {\r
- d88_sct.size = 0;\r
- }\r
- \r
- // copy to d88\r
- COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
- COPYBUFFER(dst, d88_sct.size);\r
- trkptr += sizeof(d88_sct_t) + d88_sct.size;\r
- }\r
- }\r
- d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;\r
- d88_hdr.size = trkptr;\r
- memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
- return true;\r
-}\r
-\r
-// cpdread image decoder (from MESS formats/dsk_dsk.c)\r
-\r
-bool DISK::cpdread_to_d88(int extended)\r
-{\r
- struct d88_hdr_t d88_hdr;\r
- struct d88_sct_t d88_sct;\r
- int total = 0;\r
- \r
- // get cylinder number and side number\r
- memcpy(tmp_buffer, buffer, file_size);\r
- int ncyl = tmp_buffer[0x30];\r
- int nside = tmp_buffer[0x31];\r
- \r
- // create d88 image\r
- file_size = 0;\r
- \r
- // create d88 header\r
- memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
- strcpy(d88_hdr.title, "CPDRead");\r
- d88_hdr.protect = 0; // non-protected\r
- COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
- \r
- // create tracks\r
- int trkofs = 0x100, trkofs_ptr = 0x34;\r
- int trkptr = sizeof(d88_hdr_t);\r
- \r
- for(int c = 0; c < ncyl; c++) {\r
- for(int h = 0; h < nside; h++) {\r
- // read sectors in this track\r
- uint8 *track_info = tmp_buffer + trkofs;\r
- int cyl = track_info[0x10];\r
- int side = track_info[0x11];\r
- int nsec = track_info[0x15];\r
- int size = 1 << (track_info[0x14] + 7); // standard\r
- int sctofs = trkofs + 0x100;\r
- \r
- if(nside == 1) {\r
- // double side\r
- d88_hdr.trkptr[2 * cyl] = d88_hdr.trkptr[2 * cyl + 1] = trkptr;\r
- } else {\r
- d88_hdr.trkptr[2 * cyl + side] = trkptr;\r
- }\r
- for(int s = 0; s < nsec; s++) {\r
- // get sector size\r
- uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;\r
- if(extended) {\r
- size = sector_info[6] + sector_info[7] * 256;\r
- }\r
- \r
- // create d88 sector header\r
- memset(&d88_sct, 0, sizeof(d88_sct_t));\r
- d88_sct.c = sector_info[0];\r
- d88_sct.h = sector_info[1];\r
- d88_sct.r = sector_info[2];\r
- d88_sct.n = sector_info[3];\r
- d88_sct.nsec = nsec;\r
- d88_sct.dens = 0;\r
- d88_sct.del = (sector_info[5] & 0x40) ? 0x10 : 0;\r
- d88_sct.stat = 0;\r
- d88_sct.size = size;\r
- \r
- // copy to d88\r
- COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
- COPYBUFFER(tmp_buffer + sctofs, size);\r
- trkptr += sizeof(d88_sct_t) + size;\r
- sctofs += size;\r
- total += size;\r
- }\r
- \r
- if(extended) {\r
- trkofs += tmp_buffer[trkofs_ptr++] * 256;\r
- } else {\r
- trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;\r
- }\r
- }\r
- }\r
- d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;\r
- d88_hdr.size = trkptr;\r
- memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
- return true;\r
-}\r
-\r
-// standard image decoder\r
-\r
-bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size)\r
-{\r
- struct d88_hdr_t d88_hdr;\r
- struct d88_sct_t d88_sct;\r
- int n = 0, t = 0;\r
- \r
- file_size = 0;\r
- \r
- // create d88 header\r
- memset(&d88_hdr, 0, sizeof(d88_hdr_t));\r
- strcpy(d88_hdr.title, "STANDARD");\r
- d88_hdr.protect = 0; // non-protected\r
- d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;\r
- media_type = type;\r
- COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));\r
- \r
- // sector length\r
- for(int i = 0; i < 8; i++) {\r
- if(size == (128 << i)) {\r
- n = i;\r
- break;\r
- }\r
- }\r
- \r
- // create tracks\r
- int trkptr = sizeof(d88_hdr_t);\r
- for(int c = 0; c < ncyl; c++) {\r
- for(int h = 0; h < nside; h++) {\r
- d88_hdr.trkptr[t++] = trkptr;\r
- if(nside == 1) {\r
- // double side\r
- d88_hdr.trkptr[t++] = trkptr;\r
- }\r
- \r
- // read sectors in this track\r
- for(int s = 0; s < nsec; s++) {\r
- // create d88 sector header\r
- memset(&d88_sct, 0, sizeof(d88_sct_t));\r
- d88_sct.c = c;\r
- d88_sct.h = h;\r
- d88_sct.r = s + 1;\r
- d88_sct.n = n;\r
- d88_sct.nsec = nsec;\r
- d88_sct.dens = 0;\r
- d88_sct.del = 0;\r
- d88_sct.stat = 0;\r
- d88_sct.size = size;\r
- \r
- // create sector image\r
- uint8 dst[16384];\r
- memset(dst, 0xe5, sizeof(dst));\r
- fi->Fread(dst, size, 1);\r
- \r
- // copy to d88\r
- COPYBUFFER(&d88_sct, sizeof(d88_sct_t));\r
- COPYBUFFER(dst, size);\r
- trkptr += sizeof(d88_sct_t) + size;\r
- }\r
- }\r
- }\r
- d88_hdr.size = trkptr;\r
- memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));\r
- return true;\r
-}\r
-\r
-#define STATE_VERSION 1\r
-\r
-void DISK::save_state(FILEIO* state_fio)\r
-{\r
- state_fio->FputUint32(STATE_VERSION);\r
- \r
- state_fio->Fwrite(buffer, sizeof(buffer), 1);\r
- state_fio->Fwrite(orig_path, sizeof(orig_path), 1);\r
- state_fio->Fwrite(dest_path, sizeof(dest_path), 1);\r
- state_fio->FputInt32(file_size);\r
- state_fio->FputInt32(file_offset);\r
- state_fio->FputUint32(crc32);\r
- state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);\r
- state_fio->FputBool(inserted);\r
- state_fio->FputBool(ejected);\r
- state_fio->FputBool(write_protected);\r
- state_fio->FputBool(changed);\r
- state_fio->FputUint8(media_type);\r
- state_fio->FputBool(is_standard_image);\r
- state_fio->FputBool(is_fdi_image);\r
- state_fio->FputBool(is_alpha);\r
- state_fio->Fwrite(track, sizeof(track), 1);\r
- state_fio->FputInt32(sector_num);\r
- state_fio->FputInt32(data_size_shift);\r
- state_fio->FputBool(too_many_sectors);\r
- state_fio->FputBool(no_skew);\r
- state_fio->Fwrite(sync_position, sizeof(sync_position), 1);\r
- state_fio->Fwrite(id_position, sizeof(id_position), 1);\r
- state_fio->Fwrite(data_position, sizeof(data_position), 1);\r
- state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);\r
- state_fio->FputInt32(sector_size);\r
- state_fio->Fwrite(id, sizeof(id), 1);\r
- state_fio->FputUint8(density);\r
- state_fio->FputUint8(deleted);\r
- state_fio->FputUint8(status);\r
- state_fio->FputUint8(drive_type);\r
- state_fio->FputInt32(drive_rpm);\r
- state_fio->FputBool(drive_mfm);\r
-}\r
-\r
-bool DISK::load_state(FILEIO* state_fio)\r
-{\r
- if(state_fio->FgetUint32() != STATE_VERSION) {\r
- return false;\r
- }\r
- state_fio->Fread(buffer, sizeof(buffer), 1);\r
- state_fio->Fread(orig_path, sizeof(orig_path), 1);\r
- state_fio->Fread(dest_path, sizeof(dest_path), 1);\r
- file_size = state_fio->FgetInt32();\r
- file_offset = state_fio->FgetInt32();\r
- crc32 = state_fio->FgetUint32();\r
- state_fio->Fread(fdi_header, sizeof(fdi_header), 1);\r
- inserted = state_fio->FgetBool();\r
- ejected = state_fio->FgetBool();\r
- write_protected = state_fio->FgetBool();\r
- changed = state_fio->FgetBool();\r
- media_type = state_fio->FgetUint8();\r
- is_standard_image = state_fio->FgetBool();\r
- is_fdi_image = state_fio->FgetBool();\r
- is_alpha = state_fio->FgetBool();\r
- state_fio->Fread(track, sizeof(track), 1);\r
- sector_num = state_fio->FgetInt32();\r
- data_size_shift = state_fio->FgetInt32();\r
- too_many_sectors = state_fio->FgetBool();\r
- no_skew = state_fio->FgetBool();\r
- state_fio->Fread(sync_position, sizeof(sync_position), 1);\r
- state_fio->Fread(id_position, sizeof(id_position), 1);\r
- state_fio->Fread(data_position, sizeof(data_position), 1);\r
- int offset = state_fio->FgetInt32();\r
- sector = (offset != -1) ? buffer + offset : NULL;\r
- sector_size = state_fio->FgetInt32();\r
- state_fio->Fread(id, sizeof(id), 1);\r
- density = state_fio->FgetUint8();\r
- deleted = state_fio->FgetUint8();\r
- status = state_fio->FgetUint8();\r
- drive_type = state_fio->FgetUint8();\r
- drive_rpm = state_fio->FgetInt32();\r
- drive_mfm = state_fio->FgetBool();\r
- return true;\r
-}\r
-\r
+/*
+ Skelton for retropc emulator
+
+ Author : Takeda.Toshiya
+ Date : 2006.09.16-
+
+ [ d88 handler ]
+*/
+
+#include "disk.h"
+#include "../fileio.h"
+#if defined(_USE_AGAR) || defined(_USE_SDL)
+#include "agar_logger.h"
+#endif
+
+// crc table
+static const uint16 crc_table[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+// teledisk decoder table
+static const uint8 d_code[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+ 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
+ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+ 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
+};
+static const uint8 d_len[256] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
+};
+static const int secsize[8] = {
+ 128, 256, 512, 1024, 2048, 4096, 8192, 16384
+};
+
+static uint8 tmp_buffer[DISK_BUFFER_SIZE];
+
+typedef struct {
+ int type;
+ int ncyl, nside, nsec, size;
+} fd_format_t;
+
+static const fd_format_t fd_formats[] = {
+ { MEDIA_TYPE_2D, 40, 1, 16, 256 }, // 1D 160KB
+ { MEDIA_TYPE_2D , 40, 2, 16, 256 }, // 2D 320KB
+#if defined(_MZ80B) || defined(_MZ2000) || defined(_MZ2200) || defined(_MZ2500)
+ { MEDIA_TYPE_2DD, 80, 2, 16, 256 }, // 2DD 640KB (MZ-2500)
+#else
+ { MEDIA_TYPE_2DD, 80, 2, 8, 512 }, // 2DD 640KB
+#endif
+ { MEDIA_TYPE_2DD, 80, 2, 9, 512 }, // 2DD 720KB
+ { MEDIA_TYPE_2HD, 80, 2, 15, 512 }, // 2HC 1.20MB
+ { MEDIA_TYPE_2HD, 77, 2, 8, 1024 }, // 2HD 1.25MB
+ { MEDIA_TYPE_144, 80, 2, 18, 512 }, // 2HD 1.44MB
+ { MEDIA_TYPE_144, 80, 2, 36, 512 }, // 2ED 2.88MB
+ { -1, 0, 0, 0, 0 },
+};
+
+void DISK::open(_TCHAR path[], int offset)
+{
+ // check current disk image
+ if(inserted) {
+#if defined(_USE_AGAR) || defined(_USE_SDL)
+ AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);
+#endif
+ if(_tcsicmp(orig_path, path) == 0 && file_offset == offset) {
+ return;
+ }
+ close();
+ }
+ memset(buffer, 0, sizeof(buffer));
+ media_type = MEDIA_TYPE_UNK;
+ is_standard_image = is_fdi_image = false;
+#if defined(_USE_AGAR) || defined(_USE_SDL)
+ AGAR_DebugLog(AGAR_LOG_INFO, "Open disk: %s", path);
+#endif
+ // open disk image
+ fi = new FILEIO();
+ if(fi->Fopen(path, FILEIO_READ_BINARY)) {
+ bool converted = false;
+
+ _tcscpy_s(orig_path, _MAX_PATH, path);
+ _tcscpy_s(dest_path, _MAX_PATH, path);
+ _stprintf_s(temp_path, _MAX_PATH, _T("%s.$$$"), path);
+ temporary = false;
+
+ // check if file protected
+ write_protected = fi->IsProtected(path);
+
+ // is this d88 format ?
+ if(check_file_extension(path, _T(".d88")) || check_file_extension(path, _T(".d77")) ||
+ check_file_extension(path, _T(".D88")) || check_file_extension(path, _T(".D77"))) {
+ fi->Fseek(offset + 0x1c, FILEIO_SEEK_SET);
+ file_size = fi->Fgetc();
+ file_size |= fi->Fgetc() << 8;
+ file_size |= fi->Fgetc() << 16;
+ file_size |= fi->Fgetc() << 24;
+ fi->Fseek(offset, FILEIO_SEEK_SET);
+ fi->Fread(buffer, file_size, 1);
+ file_offset = offset;
+ inserted = changed = true;
+ goto file_loaded;
+ }
+
+ fi->Fseek(0, FILEIO_SEEK_END);
+ file_size = fi->Ftell();
+ fi->Fseek(0, FILEIO_SEEK_SET);
+ file_offset = 0;
+
+#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
+ // is this 2d format ?
+ if(check_file_extension(path, _T(".2d"))) {
+ if(standard_to_d88(MEDIA_TYPE_2D, 40, 2, 16, 256)) {
+ inserted = changed = is_standard_image = true;
+ goto file_loaded;
+ }
+ fi->Fseek(0, FILEIO_SEEK_SET);
+ }
+#endif
+
+ // check image file format
+ for(int i = 0;; i++) {
+ const fd_format_t *p = &fd_formats[i];
+ if(p->type == -1) {
+ break;
+ }
+ int len = p->ncyl * p->nside * p->nsec * p->size;
+ // 4096 bytes: FDI header ???
+ if(file_size == len || (file_size == (len + 4096) && (len == 655360 || len == 1261568))) {
+ if(file_size == len + 4096) {
+ is_fdi_image = true;
+ fi->Fread(fdi_header, 4096, 1);
+ }
+ if(standard_to_d88(p->type, p->ncyl, p->nside, p->nsec, p->size)) {
+ inserted = changed = is_standard_image = true;
+ goto file_loaded;
+ }
+ }
+ }
+ if(0 < file_size && file_size <= DISK_BUFFER_SIZE) {
+ memset(buffer, 0, sizeof(buffer));
+ fi->Fread(buffer, file_size, 1);
+
+ // check d88 format (temporary)
+ if(*(uint32 *)(buffer + 0x1c) == file_size) {
+ inserted = changed = true;
+ goto file_loaded;
+ }
+ _stprintf_s(dest_path, _MAX_PATH, _T("%s.D88"), path);
+
+ // check file header
+ try {
+ if(memcmp(buffer, "TD", 2) == 0 || memcmp(buffer, "td", 2) == 0) {
+ // teledisk image file
+ inserted = changed = converted = teledisk_to_d88();
+ } else if(memcmp(buffer, "IMD", 3) == 0) {
+ // imagedisk image file
+ inserted = changed = converted = imagedisk_to_d88();
+ } else if(memcmp(buffer, "MV - CPC", 8) == 0) {
+ // standard cpdread image file
+ inserted = changed = converted = cpdread_to_d88(0);
+ } else if(memcmp(buffer, "EXTENDED", 8) == 0) {
+ // extended cpdread image file
+ inserted = changed = converted = cpdread_to_d88(1);
+ }
+ }
+ catch(...) {
+ // failed to convert the disk image
+#if defined(_USE_AGAR) || defined(_USE_SDL)
+ AGAR_DebugLog(AGAR_LOG_INFO, "EE: disk.cpp : Failed to convert disk image.");
+#endif
+ }
+ }
+file_loaded:
+ if(fi->IsOpened()) {
+ fi->Fclose();
+ }
+ if(temporary) {
+ fi->Remove(temp_path);
+ }
+ if(inserted) {
+#if 0
+ if(converted) {
+ // write image
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
+ fio->Fwrite(buffer, file_size, 1);
+ fio->Fclose();
+ }
+ delete fio;
+ }
+#endif
+ crc32 = getcrc32(buffer, file_size);
+ }
+ if(buffer[0x1a] != 0) {
+ write_protected = true;
+ }
+ if(media_type == MEDIA_TYPE_UNK) {
+ if((media_type = buffer[0x1b]) == MEDIA_TYPE_2HD) {
+ for(int trkside = 0; trkside < 164; trkside++) {
+ uint32 offset = buffer[0x20 + trkside * 4 + 0];
+ offset |= buffer[0x20 + trkside * 4 + 1] << 8;
+ offset |= buffer[0x20 + trkside * 4 + 2] << 16;
+ offset |= buffer[0x20 + trkside * 4 + 3] << 24;
+
+ if(!offset) {
+ continue;
+ }
+ // track found
+ uint8 *t = buffer + offset;
+ int sector_num = t[4] | (t[5] << 8);
+ int data_size = t[14] | (t[15] << 8);
+
+ if(sector_num >= 18 && data_size == 512) {
+ media_type = MEDIA_TYPE_144;
+ }
+ break;
+ }
+ }
+ }
+ // FIXME: ugly patch for X1turbo ALPHA and Batten Tanuki
+ is_alpha = is_batten = false;
+#if defined(_X1) || defined(_X1TWIN) || defined(_X1TURBO) || defined(_X1TURBOZ)
+ if(media_type == MEDIA_TYPE_2D) {
+ static const uint8 batten[] = {0xca, 0xde, 0xaf, 0xc3, 0xdd, 0x20, 0xc0, 0xc7, 0xb7};
+ uint32 offset = buffer[0x20] | (buffer[0x21] << 8) | (buffer[0x22] << 16) | (buffer[0x23] << 24);
+ uint8 *t = buffer + offset;
+ is_alpha = (strncmp((char *)(t + 0x11), "turbo ALPHA", 11) == 0);
+ is_batten = (memcmp((void *)(t + 0x11), batten, sizeof(batten)) == 0);
+ }
+#endif
+ }
+ delete fi;
+}
+
+void DISK::close()
+{
+ // write disk image
+ if(inserted) {
+ if(!write_protected && file_size && getcrc32(buffer, file_size) != crc32) {
+ // write image
+ FILEIO* fio = new FILEIO();
+ if(fio->Fopen(dest_path, FILEIO_READ_WRITE_BINARY)) {
+ fio->Fseek(file_offset, FILEIO_SEEK_SET);
+ } else {
+ _TCHAR tmp_path[_MAX_PATH];
+ _stprintf_s(tmp_path, _MAX_PATH, _T("temporary_saved_floppy_disk_#%d.d88"), drive_num);
+ fio->Fopen(emu->bios_path(tmp_path), FILEIO_WRITE_BINARY);
+ }
+ if(fio->IsOpened()) {
+ if(is_standard_image) {
+ if(is_fdi_image) {
+ fio->Fwrite(fdi_header, 4096, 1);
+ }
+ for(int trkside = 0; trkside < 164; trkside++) {
+ uint32 offset = buffer[0x20 + trkside * 4 + 0];
+ offset |= buffer[0x20 + trkside * 4 + 1] << 8;
+ offset |= buffer[0x20 + trkside * 4 + 2] << 16;
+ offset |= buffer[0x20 + trkside * 4 + 3] << 24;
+
+ if(!offset) {
+ break;
+ }
+ uint8* t = buffer + offset;
+ int sector_num = t[4] | (t[5] << 8);
+
+ for(int i = 0; i < sector_num; i++) {
+ int data_size = t[14] | (t[15] << 8);
+ fio->Fwrite(t + 0x10, data_size, 1);
+ t += data_size + 0x10;
+ }
+ }
+ } else {
+ fio->Fwrite(buffer, file_size, 1);
+ }
+ fio->Fclose();
+ }
+ delete fio;
+ }
+ ejected = true;
+ }
+ inserted = write_protected = false;
+ file_size = 0;
+ sector_size = sector_num = 0;
+ sector = NULL;
+}
+
+bool DISK::insert_sector(uint32 trk, uint32 side, int secnum, uint8 *chrn, uint8 *buf)
+{
+ uint8 *from;
+ uint8 *to;
+ int n_size;
+ int s_size;
+ int right;
+
+ if(secnum < 0) return false;
+
+ // This function is not implemented yet.
+ return true;
+}
+
+bool DISK::get_track(int trk, int side)
+{
+ sector_size = sector_num = 0;
+ no_skew = true;
+
+ // disk not inserted or invalid media type
+ if(!(inserted && check_media_type())) {
+ return false;
+ }
+
+ // search track
+ int trkside = trk * 2 + (side & 1);
+ if(!(0 <= trkside && trkside < 164)) {
+ return false;
+ }
+ uint32 offset = buffer[0x20 + trkside * 4 + 0];
+ offset |= buffer[0x20 + trkside * 4 + 1] << 8;
+ offset |= buffer[0x20 + trkside * 4 + 2] << 16;
+ offset |= buffer[0x20 + trkside * 4 + 3] << 24;
+
+ if(!offset) {
+ return false;
+ }
+
+ // track found
+ sector = buffer + offset;
+ sector_num = sector[4] | (sector[5] << 8);
+
+ // create each sector position in track
+ int sync_size = drive_mfm ? 12 : 6;
+ int am_size = drive_mfm ? 3 : 0;
+ int gap2_size = drive_mfm ? 22 : 11;
+
+ data_size_shift = 0;
+ too_many_sectors = false;
+retry:
+ uint8* t = sector;
+ int total = 0, gap3_size;
+
+ for(int i = 0; i < sector_num; i++) {
+ int data_size = t[14] | (t[15] << 8);
+
+ if((data_size >> data_size_shift) < 0x80) {
+ too_many_sectors = true;
+ break;
+ }
+ total += sync_size + (am_size + 1) + (4 + 2) + gap2_size + sync_size + (am_size + 1);
+ total += (data_size >> data_size_shift) + 2;
+
+ t += data_size + 0x10;
+ }
+ if(too_many_sectors) {
+ // Too many sectors in this track
+ gap3_size = 32;
+ data_size_shift = 0;
+ } else if((gap3_size = (get_track_size() - total) / (sector_num + 2)) < 12) {
+ // ID:N is modified
+ data_size_shift++;
+ goto retry;
+ }
+ t = sector;
+ total = gap3_size * 2;
+
+ for(int i = 0; i < sector_num; i++) {
+ int data_size = t[14] | (t[15] << 8);
+
+ if(too_many_sectors) {
+ total = gap3_size * 2 + (get_track_size() - gap3_size * 2) * i / sector_num;
+ }
+ sync_position[i] = total;
+ total += sync_size + (am_size + 1);
+ id_position[i] = total;
+ total += (4 + 2) + gap2_size + sync_size + (am_size + 1);
+ data_position[i] = total;
+ total += (data_size >> data_size_shift) + 2 + gap3_size;
+
+ if(t[2] != i + 1) {
+ no_skew = false;
+ }
+ t += data_size + 0x10;
+ }
+ return true;
+}
+
+bool DISK::make_track(int trk, int side)
+{
+ int track_size = get_track_size();
+
+ if(!get_track(trk, side)) {
+ // create a dummy track
+ for(int i = 0; i < track_size; i++) {
+ track[i] = rand();
+ }
+ return false;
+ }
+
+ // make track image
+ int sync_size = drive_mfm ? 12 : 6;
+ int am_size = drive_mfm ? 3 : 0;
+ int gap2_size = drive_mfm ? 22 : 11;
+ uint8 gap_data = drive_mfm ? 0x4e : 0xff;
+
+ // preamble
+ memset(track, gap_data, track_size);
+
+ if(sync_position[0] >= (sync_size + am_size + 1) + (8 + 5)) {
+ int p = (sync_position[0] - (sync_size + am_size + 1)) * 8 / (8 + 5);
+
+ // sync
+ for(int i = 0; i < sync_size; i++) {
+ track[p++] = 0x00;
+ }
+ // index mark
+ for(int i = 0; i < am_size; i++) {
+ track[p++] = 0xc2;
+ }
+ track[p++] = 0xfc;
+ }
+
+ // sectors
+ uint8 *t = sector;
+
+ for(int i = 0; i < sector_num; i++) {
+ int data_size = t[14] | (t[15] << 8);
+ int p = sync_position[i];
+
+ // sync
+ for(int j = 0; j < sync_size; j++) {
+ if(p < track_size) track[p++] = 0x00;
+ }
+ // am1
+ for(int j = 0; j < am_size; j++) {
+ if(p < track_size) track[p++] = 0xa1;
+ }
+ if(p < track_size) track[p++] = 0xfe;
+ // id
+ if(p < track_size) track[p++] = t[0];
+ if(p < track_size) track[p++] = t[1];
+ if(p < track_size) track[p++] = t[2];
+ if(p < track_size) track[p++] = t[3];
+ uint16 crc = 0;
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
+ if(p < track_size) track[p++] = crc >> 8;
+ if(p < track_size) track[p++] = crc & 0xff;
+ // gap2
+ for(int j = 0; j < gap2_size; j++) {
+ if(p < track_size) track[p++] = gap_data;
+ }
+ // sync
+ for(int j = 0; j < sync_size; j++) {
+ if(p < track_size) track[p++] = 0x00;
+ }
+ // am2
+ for(int j = 0; j < am_size; j++) {
+ if(p < track_size) track[p++] = 0xa1;
+ }
+ if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb;
+ // data
+ crc = 0;
+ for(int j = 0; j < (data_size >> data_size_shift); j++) {
+ if(p < track_size) track[p++] = t[0x10 + j];
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]);
+ }
+ if(p < track_size) track[p++] = crc >> 8;
+ if(p < track_size) track[p++] = crc & 0xff;
+
+ t += data_size + 0x10;
+ }
+ return true;
+}
+
+bool DISK::get_sector(int trk, int side, int index)
+{
+ sector_size = sector_num = 0;
+ sector = NULL;
+
+ // disk not inserted or invalid media type
+ if(!(inserted && check_media_type())) {
+ return false;
+ }
+
+ // search track
+ int trkside = trk * 2 + (side & 1);
+ if(!(0 <= trkside && trkside < 164)) {
+ return false;
+ }
+ uint32 offset = buffer[0x20 + trkside * 4 + 0];
+ offset |= buffer[0x20 + trkside * 4 + 1] << 8;
+ offset |= buffer[0x20 + trkside * 4 + 2] << 16;
+ offset |= buffer[0x20 + trkside * 4 + 3] << 24;
+
+ if(!offset) {
+ return false;
+ }
+
+ // track found
+ uint8* t = buffer + offset;
+ sector_num = t[4] | (t[5] << 8);
+
+ if(index >= sector_num) {
+ return false;
+ }
+
+ // skip sector
+ for(int i = 0; i < index; i++) {
+ t += (t[14] | (t[15] << 8)) + 0x10;
+ }
+
+ // header info
+ id[0] = t[0];
+ id[1] = t[1];
+ id[2] = t[2];
+ id[3] = t[3];
+ uint16 crc = 0;
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]);
+ crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]);
+ id[4] = crc >> 8;
+ id[5] = crc & 0xff;
+ density = t[6];
+ deleted = t[7];
+ status = t[8];
+ sector = t + 0x10;
+ sector_size = t[14] | (t[15] << 8);
+
+ return true;
+}
+
+int DISK::get_rpm()
+{
+ if(drive_rpm != 0) {
+ return drive_rpm;
+ } else if(inserted) {
+ return (media_type == MEDIA_TYPE_2HD) ? 360 : 300;
+ } else {
+ return (drive_type == DRIVE_TYPE_2HD) ? 360 : 300;
+ }
+}
+
+int DISK::get_track_size()
+{
+ if(inserted) {
+ return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
+ } else {
+ return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100;
+ }
+}
+
+double DISK::get_usec_per_bytes(int bytes)
+{
+ return 1000000.0 / (get_track_size() * (get_rpm() / 60.0)) * bytes;
+}
+
+bool DISK::check_media_type()
+{
+ switch(drive_type) {
+ case DRIVE_TYPE_2D:
+ return (media_type == MEDIA_TYPE_2D);
+ case DRIVE_TYPE_2DD:
+ return (media_type == MEDIA_TYPE_2D || media_type == MEDIA_TYPE_2DD);
+ case DRIVE_TYPE_2HD:
+ return (media_type == MEDIA_TYPE_2HD);
+ case DRIVE_TYPE_144:
+ return (media_type == MEDIA_TYPE_144);
+ case DRIVE_TYPE_UNK:
+ return true; // always okay
+ }
+ return false;
+}
+
+// teledisk image decoder
+
+/*
+ this teledisk image decoder is based on:
+
+ LZHUF.C English version 1.0 based on Japanese version 29-NOV-1988
+ LZSS coded by Haruhiko OKUMURA
+ Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
+ Edited and translated to English by Kenji RIKITAKE
+ TDLZHUF.C by WTK
+*/
+
+#define COPYBUFFER(src, size) { \
+ if(file_size + (size) > DISK_BUFFER_SIZE) { \
+ return false; \
+ } \
+ memcpy(buffer + file_size, (src), (size)); \
+ file_size += (size); \
+}
+
+bool DISK::teledisk_to_d88()
+{
+ td_hdr_t hdr;
+ td_cmt_t cmt;
+ td_trk_t trk;
+ td_sct_t sct;
+ d88_hdr_t d88_hdr;
+ d88_sct_t d88_sct;
+ uint8 obuf[512];
+
+ // check teledisk header
+ fi->Fseek(0, FILEIO_SEEK_SET);
+ fi->Fread(&hdr, sizeof(td_hdr_t), 1);
+ if(hdr.sig[0] == 't' && hdr.sig[1] == 'd') {
+ // decompress to the temporary file
+ FILEIO* fo = new FILEIO();
+ if(!fo->Fopen(temp_path, FILEIO_WRITE_BINARY)) {
+ delete fo;
+ return false;
+ }
+ int rd = 1;
+ init_decode();
+ do {
+ if((rd = decode(obuf, 512)) > 0) {
+ fo->Fwrite(obuf, rd, 1);
+ }
+ }
+ while(rd > 0);
+ fo->Fclose();
+ delete fo;
+ temporary = true;
+
+ // reopen the temporary file
+ fi->Fclose();
+ if(!fi->Fopen(temp_path, FILEIO_READ_BINARY)) {
+ return false;
+ }
+ }
+ if(hdr.flag & 0x80) {
+ // skip comment
+ fi->Fread(&cmt, sizeof(td_cmt_t), 1);
+ fi->Fseek(cmt.len, FILEIO_SEEK_CUR);
+ }
+
+ // create d88 image
+ file_size = 0;
+
+ // create d88 header
+ memset(&d88_hdr, 0, sizeof(d88_hdr_t));
+ _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "TELEDISK");
+ d88_hdr.protect = 0; // non-protected
+ COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
+
+ // create tracks
+ int trkcnt = 0, trkptr = sizeof(d88_hdr_t);
+ fi->Fread(&trk, sizeof(td_trk_t), 1);
+ while(trk.nsec != 0xff) {
+ d88_hdr.trkptr[trkcnt++] = trkptr;
+ if(hdr.sides == 1) {
+ d88_hdr.trkptr[trkcnt++] = trkptr;
+ }
+
+ // read sectors in this track
+ for(int i = 0; i < trk.nsec; i++) {
+ uint8 buf[2048], dst[2048];
+ memset(buf, 0, sizeof(buf));
+ memset(dst, 0, sizeof(dst));
+
+ // read sector header
+ fi->Fread(&sct, sizeof(td_sct_t), 1);
+
+ // create d88 sector header
+ memset(&d88_sct, 0, sizeof(d88_sct_t));
+ d88_sct.c = sct.c;
+ d88_sct.h = sct.h;
+ d88_sct.r = sct.r;
+ d88_sct.n = sct.n;
+ d88_sct.nsec = trk.nsec;
+ d88_sct.dens = (hdr.dens & 0x80) ? 0x40 : 0;
+ d88_sct.del = (sct.ctrl & 4) ? 0x10 : 0;
+ d88_sct.stat = (sct.ctrl & 2) ? 0x10 : 0; // crc?
+ d88_sct.size = secsize[sct.n & 3];
+
+ // create sector image
+ if(sct.ctrl != 0x10) {
+ // read sector source
+ int len = fi->Fgetc();
+ len += fi->Fgetc() * 256 - 1;
+ int flag = fi->Fgetc(), d = 0;
+ fi->Fread(buf, len, 1);
+
+ // convert
+ if(flag == 0) {
+ memcpy(dst, buf, len);
+ } else if(flag == 1) {
+ int len2 = buf[0] | (buf[1] << 8);
+ while(len2--) {
+ dst[d++] = buf[2];
+ dst[d++] = buf[3];
+ }
+ } else if(flag == 2) {
+ for(int s = 0; s < len;) {
+ int type = buf[s++];
+ int len2 = buf[s++];
+ if(type == 0) {
+ while(len2--) {
+ dst[d++] = buf[s++];
+ }
+ } else if(type < 5) {
+ uint8 pat[256];
+ int n = 2;
+ while(type-- > 1) {
+ n *= 2;
+ }
+ for(int j = 0; j < n; j++) {
+ pat[j] = buf[s++];
+ }
+ while(len2--) {
+ for(int j = 0; j < n; j++) {
+ dst[d++] = pat[j];
+ }
+ }
+ } else {
+ break; // unknown type
+ }
+ }
+ } else {
+ break; // unknown flag
+ }
+ } else {
+ d88_sct.size = 0;
+ }
+
+ // copy to d88
+ COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
+ COPYBUFFER(dst, d88_sct.size);
+ trkptr += sizeof(d88_sct_t) + d88_sct.size;
+ }
+ // read next track
+ fi->Fread(&trk, sizeof(td_trk_t), 1);
+ }
+ d88_hdr.type = ((hdr.dens & 3) == 2) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
+ d88_hdr.size = trkptr;
+ memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
+ return true;
+}
+
+int DISK::next_word()
+{
+ if(ibufndx >= ibufcnt) {
+ ibufndx = ibufcnt = 0;
+ memset(inbuf, 0, 512);
+ for(int i = 0; i < 512; i++) {
+ int d = fi->Fgetc();
+ if(d == EOF) {
+ if(i) {
+ break;
+ }
+ return(-1);
+ }
+ inbuf[i] = d;
+ ibufcnt = i + 1;
+ }
+ }
+ while(getlen <= 8) {
+ getbuf |= inbuf[ibufndx++] << (8 - getlen);
+ getlen += 8;
+ }
+ return 0;
+}
+
+int DISK::get_bit()
+{
+ if(next_word() < 0) {
+ return -1;
+ }
+ short i = getbuf;
+ getbuf <<= 1;
+ getlen--;
+ return (i < 0) ? 1 : 0;
+}
+
+int DISK::get_byte()
+{
+ if(next_word() != 0) {
+ return -1;
+ }
+ uint16 i = getbuf;
+ getbuf <<= 8;
+ getlen -= 8;
+ i >>= 8;
+ return (int)i;
+}
+
+void DISK::start_huff()
+{
+ int i, j;
+ for(i = 0; i < N_CHAR; i++) {
+ freq[i] = 1;
+ son[i] = i + TABLE_SIZE;
+ prnt[i + TABLE_SIZE] = i;
+ }
+ i = 0; j = N_CHAR;
+ while(j <= ROOT_POSITION) {
+ freq[j] = freq[i] + freq[i + 1];
+ son[j] = i;
+ prnt[i] = prnt[i + 1] = j;
+ i += 2; j++;
+ }
+ freq[TABLE_SIZE] = 0xffff;
+ prnt[ROOT_POSITION] = 0;
+}
+
+void DISK::reconst()
+{
+ short i, j = 0, k;
+ uint16 f, l;
+ for(i = 0; i < TABLE_SIZE; i++) {
+ if(son[i] >= TABLE_SIZE) {
+ freq[j] = (freq[i] + 1) / 2;
+ son[j] = son[i];
+ j++;
+ }
+ }
+ for(i = 0, j = N_CHAR; j < TABLE_SIZE; i += 2, j++) {
+ k = i + 1;
+ f = freq[j] = freq[i] + freq[k];
+ for(k = j - 1; f < freq[k]; k--);
+ k++;
+ l = (j - k) * 2;
+ memmove(&freq[k + 1], &freq[k], l);
+ freq[k] = f;
+ memmove(&son[k + 1], &son[k], l);
+ son[k] = i;
+ }
+ for(i = 0; i < TABLE_SIZE; i++) {
+ if((k = son[i]) >= TABLE_SIZE) {
+ prnt[k] = i;
+ } else {
+ prnt[k] = prnt[k + 1] = i;
+ }
+ }
+}
+
+void DISK::update(int c)
+{
+ int i, j, k, l;
+ if(freq[ROOT_POSITION] == MAX_FREQ) {
+ reconst();
+ }
+ c = prnt[c + TABLE_SIZE];
+ do {
+ k = ++freq[c];
+ if(k > freq[l = c + 1]) {
+ while(k > freq[++l]);
+ l--;
+ freq[c] = freq[l];
+ freq[l] = k;
+ i = son[c];
+ prnt[i] = l;
+ if(i < TABLE_SIZE) {
+ prnt[i + 1] = l;
+ }
+ j = son[l];
+ son[l] = i;
+ prnt[j] = c;
+ if(j < TABLE_SIZE) {
+ prnt[j + 1] = c;
+ }
+ son[c] = j;
+ c = l;
+ }
+ }
+ while((c = prnt[c]) != 0);
+}
+
+short DISK::decode_char()
+{
+ int ret;
+ uint16 c = son[ROOT_POSITION];
+ while(c < TABLE_SIZE) {
+ if((ret = get_bit()) < 0) {
+ return -1;
+ }
+ c += (unsigned)ret;
+ c = son[c];
+ }
+ c -= TABLE_SIZE;
+ update(c);
+ return c;
+}
+
+short DISK::decode_position()
+{
+ short bit;
+ uint16 i, j, c;
+ if((bit = get_byte()) < 0) {
+ return -1;
+ }
+ i = (uint16)bit;
+ c = (uint16)d_code[i] << 6;
+ j = d_len[i] - 2;
+ while(j--) {
+ if((bit = get_bit()) < 0) {
+ return -1;
+ }
+ i = (i << 1) + bit;
+ }
+ return (c | i & 0x3f);
+}
+
+void DISK::init_decode()
+{
+ ibufcnt= ibufndx = bufcnt = getbuf = 0;
+ getlen = 0;
+ start_huff();
+ for(int i = 0; i < STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE; i++) {
+ text_buf[i] = ' ';
+ }
+ ptr = STRING_BUFFER_SIZE - LOOKAHEAD_BUFFER_SIZE;
+}
+
+int DISK::decode(uint8 *buf, int len)
+{
+ short c, pos;
+ int count;
+ for(count = 0; count < len;) {
+ if(bufcnt == 0) {
+ if((c = decode_char()) < 0) {
+ return count;
+ }
+ if(c < 256) {
+ *(buf++) = (uint8)c;
+ text_buf[ptr++] = (uint8)c;
+ ptr &= (STRING_BUFFER_SIZE - 1);
+ count++;
+ } else {
+ if((pos = decode_position()) < 0) {
+ return count;
+ }
+ bufpos = (ptr - pos - 1) & (STRING_BUFFER_SIZE - 1);
+ bufcnt = c - 255 + THRESHOLD;
+ bufndx = 0;
+ }
+ } else {
+ while(bufndx < bufcnt && count < len) {
+ c = text_buf[(bufpos + bufndx) & (STRING_BUFFER_SIZE - 1)];
+ *(buf++) = (uint8)c;
+ bufndx++;
+ text_buf[ptr++] = (uint8)c;
+ ptr &= (STRING_BUFFER_SIZE - 1);
+ count++;
+ }
+ if(bufndx >= bufcnt) {
+ bufndx = bufcnt = 0;
+ }
+ }
+ }
+ return count;
+}
+
+// imagedisk image decoder
+
+bool DISK::imagedisk_to_d88()
+{
+ imd_trk_t trk;
+ d88_hdr_t d88_hdr;
+ d88_sct_t d88_sct;
+
+ // skip comment
+ fi->Fseek(0, FILEIO_SEEK_SET);
+ int tmp;
+ while((tmp = fi->Fgetc()) != 0x1a) {
+ if(tmp == EOF) {
+ return false;
+ }
+ }
+
+ // create d88 image
+ file_size = 0;
+
+ // create d88 header
+ memset(&d88_hdr, 0, sizeof(d88_hdr_t));
+ _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "IMAGEDISK");
+ d88_hdr.protect = 0; // non-protected
+ COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
+
+ // create tracks
+ int trkptr = sizeof(d88_hdr_t);
+ int trkcnt = 0, mode;
+
+ for(int t = 0; t < 164; t++) {
+ // check end of file
+ if(fi->Fread(&trk, sizeof(imd_trk_t), 1) != 1) {
+ break;
+ }
+ trkcnt = t;
+
+ // check track header
+ if(t == 0) {
+ mode = trk.mode % 3; // 0=500kbps, 1=300kbps, 2=250kbps
+ }
+ if(!trk.nsec) {
+ continue;
+ }
+ d88_hdr.trkptr[t] = trkptr;
+
+ // setup sector id
+ uint8 c[64], h[64], r[64];
+ fi->Fread(r, trk.nsec, 1);
+ if(trk.head & 0x80) {
+ fi->Fread(c, trk.nsec, 1);
+ } else {
+ memset(c, trk.cyl, sizeof(c));
+ }
+ if(trk.head & 0x40) {
+ fi->Fread(h, trk.nsec, 1);
+ } else {
+ memset(h, trk.head & 1, sizeof(h));
+ }
+
+ // read sectors in this track
+ for(int i = 0; i < trk.nsec; i++) {
+ // create d88 sector header
+ static const uint8 del[] = {0, 0, 0, 0x10, 0x10, 0, 0, 0x10, 0x10};
+ static const uint8 err[] = {0, 0, 0, 0, 0, 0x10, 0x10, 0x10, 0x10};
+ int sectype = fi->Fgetc();
+ if(sectype > 8) {
+ return false;
+ }
+ memset(&d88_sct, 0, sizeof(d88_sct_t));
+ d88_sct.c = c[i];
+ d88_sct.h = h[i];
+ d88_sct.r = r[i];
+ d88_sct.n = trk.size;
+ d88_sct.nsec = trk.nsec;
+ d88_sct.dens = (trk.mode < 3) ? 0x40 : 0;
+ d88_sct.del = del[sectype];
+ d88_sct.stat = err[sectype];
+ d88_sct.size = secsize[trk.size & 7];
+
+ // create sector image
+ uint8 dst[8192];
+ if(sectype == 1 || sectype == 3 || sectype == 5 || sectype == 7) {
+ // uncompressed
+ fi->Fread(dst, d88_sct.size, 1);
+ } else if(sectype == 2 || sectype == 4 || sectype == 6 || sectype == 8) {
+ // compressed
+ int tmp = fi->Fgetc();
+ memset(dst, tmp, d88_sct.size);
+ } else {
+ d88_sct.size = 0;
+ }
+
+ // copy to d88
+ COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
+ COPYBUFFER(dst, d88_sct.size);
+ trkptr += sizeof(d88_sct_t) + d88_sct.size;
+ }
+ }
+ d88_hdr.type = (mode == 0) ? MEDIA_TYPE_2HD : ((trkcnt >> 1) > 60) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2D;
+ d88_hdr.size = trkptr;
+ memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
+ return true;
+}
+
+// cpdread image decoder (from MESS formats/dsk_dsk.c)
+
+bool DISK::cpdread_to_d88(int extended)
+{
+ d88_hdr_t d88_hdr;
+ d88_sct_t d88_sct;
+ int total = 0;
+
+ // get cylinder number and side number
+ memcpy(tmp_buffer, buffer, file_size);
+ int ncyl = tmp_buffer[0x30];
+ int nside = tmp_buffer[0x31];
+
+ // create d88 image
+ file_size = 0;
+
+ // create d88 header
+ memset(&d88_hdr, 0, sizeof(d88_hdr_t));
+ _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "CPDRead");
+ d88_hdr.protect = 0; // non-protected
+ COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
+
+ // create tracks
+ int trkofs = 0x100, trkofs_ptr = 0x34;
+ int trkptr = sizeof(d88_hdr_t);
+
+ for(int c = 0; c < ncyl; c++) {
+ for(int h = 0; h < nside; h++) {
+ // read sectors in this track
+ uint8 *track_info = tmp_buffer + trkofs;
+ int cyl = track_info[0x10];
+ int side = track_info[0x11];
+ int nsec = track_info[0x15];
+ int size = 1 << (track_info[0x14] + 7); // standard
+ int sctofs = trkofs + 0x100;
+
+ if(nside == 1) {
+ // double side
+ d88_hdr.trkptr[2 * cyl] = d88_hdr.trkptr[2 * cyl + 1] = trkptr;
+ } else {
+ d88_hdr.trkptr[2 * cyl + side] = trkptr;
+ }
+ for(int s = 0; s < nsec; s++) {
+ // get sector size
+ uint8 *sector_info = tmp_buffer + trkofs + 0x18 + s * 8;
+ if(extended) {
+ size = sector_info[6] + sector_info[7] * 256;
+ }
+
+ // create d88 sector header
+ memset(&d88_sct, 0, sizeof(d88_sct_t));
+ d88_sct.c = sector_info[0];
+ d88_sct.h = sector_info[1];
+ d88_sct.r = sector_info[2];
+ d88_sct.n = sector_info[3];
+ d88_sct.nsec = nsec;
+ d88_sct.dens = 0;
+ d88_sct.del = (sector_info[5] & 0x40) ? 0x10 : 0;
+ d88_sct.stat = 0;
+ d88_sct.size = size;
+
+ // copy to d88
+ COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
+ COPYBUFFER(tmp_buffer + sctofs, size);
+ trkptr += sizeof(d88_sct_t) + size;
+ sctofs += size;
+ total += size;
+ }
+
+ if(extended) {
+ trkofs += tmp_buffer[trkofs_ptr++] * 256;
+ } else {
+ trkofs += tmp_buffer[0x32] + tmp_buffer[0x33] * 256;
+ }
+ }
+ }
+ d88_hdr.type = (total < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (total < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
+ d88_hdr.size = trkptr;
+ memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
+ return true;
+}
+
+// standard image decoder
+
+bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size)
+{
+ d88_hdr_t d88_hdr;
+ d88_sct_t d88_sct;
+ int n = 0, t = 0;
+
+ file_size = 0;
+
+ // create d88 header
+ memset(&d88_hdr, 0, sizeof(d88_hdr_t));
+ _strcpy_s(d88_hdr.title, sizeof(d88_hdr.title), "STANDARD");
+ d88_hdr.protect = 0; // non-protected
+ d88_hdr.type = (type == MEDIA_TYPE_144) ? MEDIA_TYPE_2HD : type;
+ media_type = type;
+ COPYBUFFER(&d88_hdr, sizeof(d88_hdr_t));
+
+ // sector length
+ for(int i = 0; i < 8; i++) {
+ if(size == (128 << i)) {
+ n = i;
+ break;
+ }
+ }
+
+ // create tracks
+ int trkptr = sizeof(d88_hdr_t);
+ for(int c = 0; c < ncyl; c++) {
+ for(int h = 0; h < nside; h++) {
+ d88_hdr.trkptr[t++] = trkptr;
+ if(nside == 1) {
+ // double side
+ d88_hdr.trkptr[t++] = trkptr;
+ }
+
+ // read sectors in this track
+ for(int s = 0; s < nsec; s++) {
+ // create d88 sector header
+ memset(&d88_sct, 0, sizeof(d88_sct_t));
+ d88_sct.c = c;
+ d88_sct.h = h;
+ d88_sct.r = s + 1;
+ d88_sct.n = n;
+ d88_sct.nsec = nsec;
+ d88_sct.dens = 0;
+ d88_sct.del = 0;
+ d88_sct.stat = 0;
+ d88_sct.size = size;
+
+ // create sector image
+ uint8 dst[16384];
+ memset(dst, 0xe5, sizeof(dst));
+ fi->Fread(dst, size, 1);
+
+ // copy to d88
+ COPYBUFFER(&d88_sct, sizeof(d88_sct_t));
+ COPYBUFFER(dst, size);
+ trkptr += sizeof(d88_sct_t) + size;
+ }
+ }
+ }
+ d88_hdr.size = trkptr;
+ memcpy(buffer, &d88_hdr, sizeof(d88_hdr_t));
+ return true;
+}
+
+#define STATE_VERSION 2
+
+void DISK::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+
+ state_fio->Fwrite(buffer, sizeof(buffer), 1);
+ state_fio->Fwrite(orig_path, sizeof(orig_path), 1);
+ state_fio->Fwrite(dest_path, sizeof(dest_path), 1);
+ state_fio->FputInt32(file_size);
+ state_fio->FputInt32(file_offset);
+ state_fio->FputUint32(crc32);
+ state_fio->Fwrite(fdi_header, sizeof(fdi_header), 1);
+ state_fio->FputBool(inserted);
+ state_fio->FputBool(ejected);
+ state_fio->FputBool(write_protected);
+ state_fio->FputBool(changed);
+ state_fio->FputUint8(media_type);
+ state_fio->FputBool(is_standard_image);
+ state_fio->FputBool(is_fdi_image);
+ state_fio->FputBool(is_alpha);
+ state_fio->FputBool(is_batten);
+ state_fio->Fwrite(track, sizeof(track), 1);
+ state_fio->FputInt32(sector_num);
+ state_fio->FputInt32(data_size_shift);
+ state_fio->FputBool(too_many_sectors);
+ state_fio->FputBool(no_skew);
+ state_fio->Fwrite(sync_position, sizeof(sync_position), 1);
+ state_fio->Fwrite(id_position, sizeof(id_position), 1);
+ state_fio->Fwrite(data_position, sizeof(data_position), 1);
+ state_fio->FputInt32(sector ? (int)(sector - buffer) : -1);
+ state_fio->FputInt32(sector_size);
+ state_fio->Fwrite(id, sizeof(id), 1);
+ state_fio->FputUint8(density);
+ state_fio->FputUint8(deleted);
+ state_fio->FputUint8(status);
+ state_fio->FputUint8(drive_type);
+ state_fio->FputInt32(drive_rpm);
+ state_fio->FputBool(drive_mfm);
+}
+
+bool DISK::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ state_fio->Fread(buffer, sizeof(buffer), 1);
+ state_fio->Fread(orig_path, sizeof(orig_path), 1);
+ state_fio->Fread(dest_path, sizeof(dest_path), 1);
+ file_size = state_fio->FgetInt32();
+ file_offset = state_fio->FgetInt32();
+ crc32 = state_fio->FgetUint32();
+ state_fio->Fread(fdi_header, sizeof(fdi_header), 1);
+ inserted = state_fio->FgetBool();
+ ejected = state_fio->FgetBool();
+ write_protected = state_fio->FgetBool();
+ changed = state_fio->FgetBool();
+ media_type = state_fio->FgetUint8();
+ is_standard_image = state_fio->FgetBool();
+ is_fdi_image = state_fio->FgetBool();
+ is_alpha = state_fio->FgetBool();
+ is_batten = state_fio->FgetBool();
+ state_fio->Fread(track, sizeof(track), 1);
+ sector_num = state_fio->FgetInt32();
+ data_size_shift = state_fio->FgetInt32();
+ too_many_sectors = state_fio->FgetBool();
+ no_skew = state_fio->FgetBool();
+ state_fio->Fread(sync_position, sizeof(sync_position), 1);
+ state_fio->Fread(id_position, sizeof(id_position), 1);
+ state_fio->Fread(data_position, sizeof(data_position), 1);
+ int offset = state_fio->FgetInt32();
+ sector = (offset != -1) ? buffer + offset : NULL;
+ sector_size = state_fio->FgetInt32();
+ state_fio->Fread(id, sizeof(id), 1);
+ density = state_fio->FgetUint8();
+ deleted = state_fio->FgetUint8();
+ status = state_fio->FgetUint8();
+ drive_type = state_fio->FgetUint8();
+ drive_rpm = state_fio->FgetInt32();
+ drive_mfm = state_fio->FgetBool();
+ return true;
+}
+