/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Handle the New Floppy Image dialog. * * Version: @(#)win_new_floppy.c 1.0.0 2018/01/18 * * Authors: Miran Grca, * * Copyright 2016-2018 Miran Grca. */ #define UNICODE #define BITMAP WINDOWS_BITMAP #include #include #undef BITMAP #include #include #include #include #include #include "../86box.h" #include "../plat.h" #include "../random.h" #include "../ui.h" #include "win.h" typedef struct { int hole; int sides; int data_rate; int encoding; int rpm; int tracks; int sectors; /* For IMG and Japanese FDI only. */ int sector_len; /* For IMG and Japanese FDI only. */ int media_desc; int spc; int num_fats; int spfat; int root_dir_entries; } disk_size_t; disk_size_t disk_sizes[12] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xFE, 2, 2, 1, 112 }, /* 160k */ { 0, 1, 2, 1, 0, 40, 9, 2, 0xFC, 2, 2, 1, 112 }, /* 180k */ { 0, 2, 2, 1, 0, 40, 8, 2, 0xFF, 2, 2, 1, 112 }, /* 320k */ { 0, 2, 2, 1, 0, 40, 9, 2, 0xFD, 2, 2, 2, 112 }, /* 360k */ { 0, 2, 2, 1, 0, 80, 8, 2, 0xFB, 2, 2, 2, 112 }, /* 640k */ { 0, 2, 2, 1, 0, 80, 9, 2, 0xF9, 2, 2, 3, 112 }, /* 720k */ { 1, 2, 0, 1, 1, 80, 15, 2, 0xF9, 1, 2, 7, 224 }, /* 1.2M */ { 1, 2, 0, 1, 1, 77, 8, 3, 0xFE, 1, 2, 2, 192 }, /* 1.25M */ { 1, 2, 0, 1, 0, 80, 18, 2, 0xF0, 1, 2, 9, 224 }, /* 1.44M */ { 1, 2, 0, 1, 0, 80, 21, 2, 0xF0, 2, 2, 5, 16 }, /* DMF cluster 1024 */ { 1, 2, 0, 1, 0, 80, 21, 2, 0xF0, 4, 2, 3, 16 }, /* DMF cluster 2048 */ { 2, 2, 3, 1, 0, 80, 36, 2, 0xF0, 2, 2, 9, 240 } }; /* 2.88M */ static char *empty; static int create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) { FILE *f; uint32_t magic = 0x46423638; uint16_t version = 0x020B; uint16_t dflags = 0; uint16_t tflags = 0; uint16_t index_hole_pos = 0; uint32_t tarray[512]; uint32_t array_size, array_size2; uint32_t track_base, track_size; int i; dflags = 0; /* Has surface data? - Assume no for now. */ dflags |= (disk_size.hole << 1); /* Hole */ dflags |= ((disk_size.sides - 1) << 3); /* Sides. */ dflags |= (0 << 4); /* Write protect? - Assume no for now. */ dflags |= (rpm_mode << 5); /* RPM mode. */ dflags |= (0 << 7); /* Has extra bit cells? - Assume no for now. */ tflags = disk_size.data_rate; /* Data rate. */ tflags |= (disk_size.encoding << 3); /* Encoding. */ tflags |= (disk_size.rpm << 5); /* RPM. */ switch (disk_size.hole) { case 0: case 1: default: switch(rpm_mode) { case 1: array_size = 25250; break; case 2: array_size = 25374; break; case 3: array_size = 25750; break; default: array_size = 25000; break; } break; case 2: switch(rpm_mode) { case 1: array_size = 50500; break; case 2: array_size = 50750; break; case 3: array_size = 51000; break; default: array_size = 50000; break; } break; } array_size2 = (array_size << 3); array_size = (array_size2 >> 4) << 1; if (array_size2 & 15) array_size += 2; empty = (char *) malloc(array_size); memset(tarray, 0, 2048); memset(empty, 0, array_size); f = plat_fopen(file_name, L"wb"); if (!f) return 0; fwrite(&magic, 4, 1, f); fwrite(&version, 2, 1, f); fwrite(&dflags, 2, 1, f); track_size = array_size + 6; track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024); for (i = 0; i < disk_size.tracks * disk_size.sides; i++) tarray[i] = track_base + (i * track_size); fwrite(tarray, 1, (disk_size.sides == 2) ? 2048 : 1024, f); for (i = 0; i < disk_size.tracks * disk_size.sides; i++) { fwrite(&tflags, 2, 1, f); fwrite(&index_hole_pos, 4, 1, f); fwrite(empty, 1, array_size, f); } free(empty); fclose(f); return 1; } static int create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) { FILE *f; uint32_t total_size = 0; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint32_t root_dir_bytes = 0; uint32_t fat_size = 0; uint32_t fat1_offs = 0; uint32_t fat2_offs = 0; uint32_t zero_bytes = 0; uint16_t base = 0x1000; f = plat_fopen(file_name, L"wb"); if (!f) return 0; sector_bytes = (128 << disk_size.sector_len); total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; total_size = total_sectors * sector_bytes; root_dir_bytes = (disk_size.root_dir_entries << 5); fat_size = (disk_size.spfat * sector_bytes); fat1_offs = sector_bytes; fat2_offs = fat1_offs + fat_size; zero_bytes = fat2_offs + fat_size + root_dir_bytes; if (is_fdi) { empty = (char *) malloc(base); memset(empty, 0, base); *(uint32_t *) &(empty[0x08]) = (uint32_t) base; *(uint32_t *) &(empty[0x0C]) = total_size; *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; fwrite(empty, 1, base, f); free(empty); } empty = (char *) malloc(total_size); memset(empty, 0x00, zero_bytes); memset(empty + zero_bytes, 0xF6, total_size - zero_bytes); empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */ empty[0x01] = 0x58; empty[0x02] = 0x90; empty[0x03] = 0x38; /* '86BOX5.0' OEM ID. */ empty[0x04] = 0x36; empty[0x05] = 0x42; empty[0x06] = 0x4F; empty[0x07] = 0x58; empty[0x08] = 0x35; empty[0x09] = 0x2E; empty[0x0A] = 0x30; *(uint16_t *) &(empty[0x0B]) = (uint16_t) sector_bytes; *(uint8_t *) &(empty[0x0D]) = (uint8_t) disk_size.spc; *(uint16_t *) &(empty[0x0E]) = (uint16_t) 1; *(uint8_t *) &(empty[0x10]) = (uint8_t) disk_size.num_fats; *(uint16_t *) &(empty[0x11]) = (uint16_t) disk_size.root_dir_entries; *(uint16_t *) &(empty[0x13]) = (uint16_t) total_sectors; *(uint8_t *) &(empty[0x15]) = (uint8_t) disk_size.media_desc; *(uint16_t *) &(empty[0x16]) = (uint16_t) disk_size.spfat; *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sectors; *(uint8_t *) &(empty[0x1A]) = (uint8_t) disk_size.sides; empty[0x26] = 0x29; /* ')' followed by randomly-generated volume serial number. */ empty[0x27] = random_generate(); empty[0x28] = random_generate(); empty[0x29] = random_generate(); empty[0x2A] = random_generate(); memset(&(empty[0x2B]), 0x20, 11); empty[0x36] = 'F'; empty[0x37] = 'A'; empty[0x38] = 'T'; empty[0x39] = '1'; empty[0x3A] = '2'; empty[0x1FE] = 0x55; empty[0x1FF] = 0xAA; empty[fat1_offs + 0x00] = empty[fat2_offs + 0x00] = empty[0x15]; empty[fat1_offs + 0x01] = empty[fat2_offs + 0x01] = empty[0xFF]; empty[fat1_offs + 0x02] = empty[fat2_offs + 0x02] = empty[0xFF]; fwrite(empty, 1, total_size, f); free(empty); fclose(f); return 1; } static int fdd_id, sb_part; static int file_type = 0; /* 0 = IMG, 1 = Japanese FDI, 2 = 86F */ static wchar_t fd_file_name[512]; /* Show a MessageBox dialog. This is nasty, I know. --FvK */ static int new_floppy_msgbox(HWND hwnd, int type, void *arg) { HWND h; int i; h = hwndMain; hwndMain = hwnd; i = ui_msgbox(type, arg); hwndMain = h; return(i); } #ifdef __amd64__ static LRESULT CALLBACK #else static BOOL CALLBACK #endif NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; int i = 0; int wcs_len, ext_offs; wchar_t *ext; uint8_t disk_size, rpm_mode; int ret; FILE *f; switch (message) { case WM_INITDIALOG: plat_pause(1); memset(fd_file_name, 0, 512 * sizeof(wchar_t)); h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); for (i = 0; i < 12; i++) SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_5888 + i)); EnableWindow(h, FALSE); h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); for (i = 0; i < 4; i++) SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_6144 + i)); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); h = GetDlgItem(hdlg, IDT_1751); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); h = GetDlgItem(hdlg, IDOK); EnableWindow(h, FALSE); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); disk_size = SendMessage(h, CB_GETCURSEL, 0, 0); if (file_type == 2) { h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); rpm_mode = SendMessage(h, CB_GETCURSEL, 0, 0); ret = create_86f(fd_file_name, disk_sizes[disk_size], rpm_mode); } else ret = create_sector_image(fd_file_name, disk_sizes[disk_size], file_type); if (ret) ui_sb_mount_floppy_img(fdd_id, sb_part, 0, fd_file_name); else { new_floppy_msgbox(hdlg, MBX_ERROR, (wchar_t *)IDS_4108); return TRUE; } case IDCANCEL: EndDialog(hdlg, 0); plat_pause(0); return TRUE; case IDC_CFILE: if (!file_dlg_w(hdlg, plat_get_string(IDS_2174), L"", 1)) { h = GetDlgItem(hdlg, IDC_EDIT_FILE_NAME); f = _wfopen(wopenfilestring, L"rb"); if (f != NULL) { fclose(f); if (new_floppy_msgbox(hdlg, MBX_QUESTION, (wchar_t *)IDS_4111) != 0) /* yes */ return FALSE; } SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); memset(fd_file_name, 0, sizeof(fd_file_name)); wcscpy(fd_file_name, wopenfilestring); h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); EnableWindow(h, TRUE); wcs_len = wcslen(wopenfilestring); ext_offs = wcs_len - 4; ext = &(wopenfilestring[ext_offs]); if ((wcs_len >= 4) && !wcsicmp(ext, L".FDI")) file_type = 1; else if ((wcs_len >= 4) && !wcsicmp(ext, L".86F")) file_type = 2; else file_type = 0; h = GetDlgItem(hdlg, IDT_1751); if (file_type == 2) { EnableWindow(h, TRUE); ShowWindow(h, SW_SHOW); } else { EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); } h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); if (file_type == 2) { EnableWindow(h, TRUE); ShowWindow(h, SW_SHOW); } else { EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); } h = GetDlgItem(hdlg, IDOK); EnableWindow(h, TRUE); return TRUE; } else return FALSE; default: break; } break; } return(FALSE); } void NewFloppyDialogCreate(HWND hwnd, int id, int part) { fdd_id = id; sb_part = part; DialogBox(hinstance, (LPCTSTR)DLG_NEW_FLOPPY, hwnd, NewFloppyDialogProcedure); }