From 507031a6e6379c9f809a69c7acc80f6d352f5544 Mon Sep 17 00:00:00 2001 From: Ian C Date: Tue, 28 May 2019 14:11:25 +0000 Subject: CPC code now loads disk image contents. Directory manipulation still to do. --- cpc.c | 497 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100644 cpc.c (limited to 'cpc.c') diff --git a/cpc.c b/cpc.c new file mode 100644 index 0000000..1eb2459 --- /dev/null +++ b/cpc.c @@ -0,0 +1,497 @@ +/* + + DiskImageTool - Tool for manipulating disk images - CPC DSK images + + Copyright (C) 2019 Ian Cowburn (ianc@noddybox.co.uk) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ------------------------------------------------------------------------- + + CPC DSK images + +*/ +#include +#include +#include +#include + +#include "handler.h" +#include "util.h" +#include "cpc.h" + +/* ---------------------------------------- TYPES +*/ + +typedef struct +{ + int id; + int size; + int reg1; + int reg2; + char data[512]; +} Sector; + +typedef struct +{ + int track_no; + int side_no; + int no_sectors; + int track_size; + int sector_size; + int gap3_length; + int filler_byte; + int formatted; + Sector sector[10]; +} Track; + +typedef struct +{ + int no_tracks; + Track track[80]; +} Disk; + +typedef enum +{ + UnknownFormat, + FormatIBM, + FormatSystem, + FormatData +} DiskFormat; + +/* ---------------------------------------- GLOBALS +*/ +static char g_last_error[4096]; +static int g_is_extended; +static unsigned char *g_mem; +static size_t g_size; +static Disk g_disk; +static DiskFormat g_format; + +/* ---------------------------------------- UTILS +*/ +static int ImageError(const char *format, ...) +{ + va_list va; + + va_start(va, format); + vsnprintf(g_last_error, sizeof g_last_error, format, va); + va_end(va); + + if (g_mem) + { + free(g_mem); + g_mem = NULL; + g_size = 0; + } + + return 0; +} + +static int GetWord(int offset) +{ + int i; + + i = g_mem[offset]; + i|= (int)g_mem[offset+1] * 256; + + return i; +} + +static int LowSectorID(int track) +{ + int f; + int id = 256; + + for(f = 0; f < g_disk.track[f].no_sectors; f++) + { + if (g_disk.track[track].sector[f].id < id) + { + id = g_disk.track[track].sector[f].id; + } + } + + return id; +} + +static int SectorSize(int size) +{ + return 128 << size; +} + +/* ---------------------------------------- HANDLER INTERFACES +*/ +static const char *CPC_last_error(void) +{ + return g_last_error; +} + +static void CPC_list_files(void) +{ +} + +static void CPC_list_info(void) +{ + int f; + + printf("Disk format: "); + + switch(g_format) + { + case FormatIBM: + printf("IBM\n"); + break; + case FormatSystem: + printf("System\n"); + break; + case FormatData: + printf("Data\n"); + break; + case UnknownFormat: + printf("Unknown\n"); + return; + } + + printf("No tracks: %d\n", g_disk.no_tracks); + + for(f = 0; f < g_disk.no_tracks; f++) + { + printf("Track %2d : ", f); + + if (g_disk.track[f].formatted) + { + int n; + + printf(" [ "); + + for(n = 0; n < g_disk.track[f].no_sectors; n++) + { + printf("%2.2x %3.3x ", (unsigned)g_disk.track[f].sector[n].id, + (unsigned)SectorSize + (g_disk.track[f].sector[n].size)); + } + + printf("]\n"); + } + else + { + printf("unformatted\n"); + } + } +} + +static int CPC_is_my_file(const void *buff, size_t buffsize) +{ + return CompareMem(buff, "MV - CPC") == 0 || + CompareMem(buff, "EXTENDED") == 0; +} + +static int CPC_open_image(void *buff, size_t buffsize) +{ + int f,n; + + if (CompareMem(buff, "MV - CPC") == 0) + { + g_is_extended = 0; + } + else if (CompareMem(buff, "EXTENDED") == 0) + { + g_is_extended = 1; + } + else + { + return ImageError("Can't find disk file signature"); + } + + g_mem = buff; + g_size = buffsize; + + memset(&g_disk, 0, sizeof g_disk); + + if (g_is_extended) + { + int no_sides; + int total_track_length = 0; + + no_sides = g_mem[0x31]; + + if (no_sides > 1) + { + return ImageError("Invalid number of sides %d", no_sides); + } + + g_disk.no_tracks = g_mem[0x30]; + + if (g_disk.no_tracks > 80) + { + return ImageError("Invalid number of tracks %d", + g_disk.no_tracks); + } + + for(f = 0; f < g_disk.no_tracks; f++) + { + int offset; + int track_size; + int sector_size; + int data_length; + int total_length = 0; + + track_size = g_mem[0x34 + f] * 256; + offset = 0x100 + total_track_length; + total_track_length += track_size; + + g_disk.track[f].formatted = track_size != 0; + + if (g_disk.track[f].formatted) + { + if (CompareMem(g_mem + offset, "Track-Info")) + { + return ImageError + ("Missing 'Track-Info' at offset %d on track %d", + offset, f); + } + + g_disk.track[f].track_no = g_mem[offset + 0x10]; + g_disk.track[f].side_no = g_mem[offset + 0x11]; + g_disk.track[f].sector_size = g_mem[offset + 0x14]; + g_disk.track[f].gap3_length = g_mem[offset + 0x16]; + g_disk.track[f].filler_byte = g_mem[offset + 0x17]; + g_disk.track[f].no_sectors = g_mem[offset + 0x15]; + + if (g_disk.track[f].no_sectors > 10) + { + return ImageError + ("Invalid number of sectors %d on track %d", + g_disk.track[f].no_sectors, + g_disk.track[f].track_no); + } + + sector_size = 128 << g_disk.track[f].sector_size; + + if (sector_size > 512) + { + return ImageError("Invalid sector size %d", sector_size); + } + + for(n = 0; n < g_disk.track[f].no_sectors; n++) + { + int sec_offset; + + sec_offset = offset + 0x18 + n * 8; + + g_disk.track[f].sector[n].id = g_mem[sec_offset + 0x02]; + g_disk.track[f].sector[n].size = g_mem[sec_offset + 0x03]; + g_disk.track[f].sector[n].reg1 = g_mem[sec_offset + 0x04]; + g_disk.track[f].sector[n].reg2 = g_mem[sec_offset + 0x05]; + + data_length = GetWord(sec_offset + 0x06); + sector_size = SectorSize(g_disk.track[f].sector[n].size); + + if (sector_size > 512 || data_length > 512) + { + return ImageError + ("Invalid sector size %d on track %d, sector %d", + sector_size, f, n); + } + + memcpy(g_disk.track[f].sector[n].data, + g_mem + offset + 0x100 + total_length, + data_length); + + total_length += data_length; + } + } + } + } + else + { + int no_sides; + int track_size; + + no_sides = g_mem[0x31]; + + if (no_sides > 1) + { + return ImageError("Invalid number of sides %d", no_sides); + } + + g_disk.no_tracks = g_mem[0x30]; + + if (g_disk.no_tracks > 80) + { + return ImageError("Invalid number of tracks %d", + g_disk.no_tracks); + } + + track_size = GetWord(0x32); + + for(f = 0; f < g_disk.no_tracks; f++) + { + int offset; + int sector_size; + + offset = 0x100 + f * track_size; + + if (CompareMem(g_mem + offset, "Track-Info")) + { + return ImageError + ("Missing 'Track-Info' at offset %d on track %d", + offset, f); + } + + g_disk.track[f].track_no = g_mem[offset + 0x10]; + g_disk.track[f].side_no = g_mem[offset + 0x11]; + g_disk.track[f].sector_size = g_mem[offset + 0x14]; + g_disk.track[f].gap3_length = g_mem[offset + 0x16]; + g_disk.track[f].filler_byte = g_mem[offset + 0x17]; + g_disk.track[f].no_sectors = g_mem[offset + 0x15]; + g_disk.track[f].formatted = 1; + + if (g_disk.track[f].no_sectors > 10) + { + return ImageError("Invalid number of sectors %d on track %d", + g_disk.track[f].no_sectors, + g_disk.track[f].track_no); + } + + sector_size = SectorSize(g_disk.track[f].sector_size); + + if (sector_size > 512) + { + return ImageError("Invalid sector size %d", sector_size); + } + + for(n = 0; n < g_disk.track[f].no_sectors; n++) + { + int sec_offset; + + sec_offset = offset + 0x18 + n * 8; + + g_disk.track[f].sector[n].id = g_mem[sec_offset + 0x02]; + g_disk.track[f].sector[n].size = g_mem[sec_offset + 0x03]; + g_disk.track[f].sector[n].reg1 = g_mem[sec_offset + 0x04]; + g_disk.track[f].sector[n].reg2 = g_mem[sec_offset + 0x05]; + + sector_size = SectorSize(g_disk.track[f].sector[n].size); + + if (sector_size > 512) + { + return ImageError + ("Invalid sector size %d on track %d, sector %d", + SectorSize(g_disk.track[f].sector[n].size)); + } + + memcpy(g_disk.track[f].sector[n].data, + g_mem + offset + 0x100 + sector_size * n, + sector_size); + } + } + } + + switch(LowSectorID(0)) + { + case 1: + if (g_disk.track[0].no_sectors == 8) + { + g_format = FormatIBM; + } + break; + + case 65: + g_format = FormatSystem; + break; + + case 193: + g_format = FormatData; + break; + + default: + g_format = UnknownFormat; + break; + } + + if (g_format == UnknownFormat) + { + return ImageError("Unknown format"); + } + + return 1; +} + +static int CPC_close_image(const char *name) +{ + if (name) + { + } + + if (g_mem) + { + free(g_mem); + g_mem = NULL; + g_size = 0; + } + + return 0; +} + +static int CPC_get_file(const char *name, const char *path) +{ + strcpy(g_last_error, "Get file not yet done"); + return 0; +} + +static int CPC_put_file(const char *name, const char *path) +{ + strcpy(g_last_error, "Put file not yet done"); + return 0; +} + +static int CPC_delete_file(const char *name) +{ + strcpy(g_last_error, "Delete not yet done"); + return 0; +} + +static int CPC_create(const char *path) +{ + strcpy(g_last_error, "Create not yet done"); + return 0; +} + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void CPC_Initialise(void) +{ + Handler handler = {0}; + + handler.id = "cpc"; + handler.name = "CPC DSK handler"; + + handler.last_error = CPC_last_error; + handler.list_files = CPC_list_files; + handler.list_info = CPC_list_info; + handler.is_my_file = CPC_is_my_file; + handler.open_image = CPC_open_image; + handler.close_image = CPC_close_image; + handler.get_file = CPC_get_file; + handler.put_file = CPC_put_file; + handler.delete_file = CPC_delete_file; + handler.create = CPC_create; + + DITOOL_Register(&handler); +} + +/* +vim: ai sw=4 ts=8 expandtab +*/ -- cgit v1.2.3