diff options
Diffstat (limited to 'src/tools/imgtool/modules/concept.c')
-rw-r--r-- | src/tools/imgtool/modules/concept.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/src/tools/imgtool/modules/concept.c b/src/tools/imgtool/modules/concept.c new file mode 100644 index 00000000000..a5c5a37b1ad --- /dev/null +++ b/src/tools/imgtool/modules/concept.c @@ -0,0 +1,492 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + Handlers for concept floppy images + + Disk images are in MESS format. + + Raphael Nabet, 2003 +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include "imgtool.h" + +struct UINT16xE +{ + UINT8 bytes[2]; +}; + +/* + get_UINT16xE + + Read a 16-bit word, whether it is little-endian or big-endian + + little_endian (I): non-zero if word is little-endian, zero if word is + big-endian + word (I): pointer to word to read + + Returns value of word in native format +*/ +INLINE UINT16 get_UINT16xE(int little_endian, UINT16xE word) +{ + return little_endian ? (word.bytes[0] | (word.bytes[1] << 8)) : ((word.bytes[0] << 8) | word.bytes[1]); +} + +#if 0 +/* + set_UINT16xE + + Write a 16-bit word, whether it is little-endian or big-endian + + little_endian (I): non-zero if word is little-endian, zero if word is + big-endian + word (O): pointer to word to write + data (I): value to write in word, in native format +*/ +INLINE void set_UINT16xE(int little_endian, UINT16xE *word, UINT16 data) +{ + if (little_endian) + { + word->bytes[0] = data & 0xff; + word->bytes[1] = (data >> 8) & 0xff; + } + else + { + word->bytes[0] = (data >> 8) & 0xff; + word->bytes[1] = data & 0xff; + } +} +#endif + +/* + Disk structure: + + Track 0 Sector 0 & 1: bootstrap loader + Track 0 Sector 2 through 5: disk directory + Remaining sectors are used for data. +*/ + +/* + device directory record (Disk sector 2-5) +*/ + +struct concept_vol_hdr_entry +{ + UINT16xE first_block; + UINT16xE next_block; + UINT16xE ftype; + + unsigned char volname[8]; + UINT16xE last_block; + UINT16xE num_files; + UINT16xE last_boot; + UINT16xE last_access; + char mem_flipped; + char disk_flipped; + UINT16xE unused; +}; + +struct concept_file_dir_entry +{ + UINT16xE first_block; + UINT16xE next_block; + UINT16xE ftype; + + unsigned char filename[16]; + UINT16xE last_byte; + UINT16xE last_access; +}; + +struct concept_dev_dir +{ + concept_vol_hdr_entry vol_hdr; + concept_file_dir_entry file_dir[77]; + char unused[20]; +}; + +/* + concept disk image descriptor +*/ +struct concept_image +{ + imgtool_stream *file_handle; /* imgtool file handle */ + concept_dev_dir dev_dir; /* cached copy of device directory */ +}; + +/* + concept catalog iterator, used when imgtool reads the catalog +*/ +struct concept_iterator +{ + concept_image *image; + int index; /* current index */ +}; + + +static imgtoolerr_t concept_image_init(imgtool_image *img, imgtool_stream *f); +static void concept_image_exit(imgtool_image *img); +static void concept_image_info(imgtool_image *img, char *string, size_t len); +static imgtoolerr_t concept_image_beginenum(imgtool_directory *enumeration, const char *path); +static imgtoolerr_t concept_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent); +static void concept_image_closeenum(imgtool_directory *enumeration); +static imgtoolerr_t concept_image_freespace(imgtool_partition *partition, UINT64 *size); +static imgtoolerr_t concept_image_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); +#if 0 +static imgtoolerr_t concept_image_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions); +static imgtoolerr_t concept_image_deletefile(imgtool_partition *partition, const char *filename); +static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool_stream *f, option_resolution *createoptions); +#endif + +void concept_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(concept_image); break; + case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(concept_iterator); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "concept"); break; + case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Concept floppy disk image"); break; + case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "img"); break; + case IMGTOOLINFO_STR_EOLN: strcpy(info->s = imgtool_temp_str(), "\r"); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case IMGTOOLINFO_PTR_OPEN: info->open = concept_image_init; break; + case IMGTOOLINFO_PTR_CLOSE: info->close = concept_image_exit; break; + case IMGTOOLINFO_PTR_INFO: info->info = concept_image_info; break; + case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = concept_image_beginenum; break; + case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = concept_image_nextenum; break; + case IMGTOOLINFO_PTR_CLOSE_ENUM: info->close_enum = concept_image_closeenum; break; + case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = concept_image_freespace; break; + case IMGTOOLINFO_PTR_READ_FILE: info->read_file = concept_image_readfile; break; + case IMGTOOLINFO_PTR_WRITE_FILE: /* info->write_file = concept_image_writefile */; break; + case IMGTOOLINFO_PTR_DELETE_FILE: /* info->delete_file = concept_image_deletefile */; break; + case IMGTOOLINFO_PTR_CREATE: /* info->create = concept_image_create */; break; + } +} + +/* + read_physical_record + + Read one 512-byte physical record from a disk image + + file_handle: imgtool file handle + secnum: physical record address + dest: pointer to destination buffer + + Return non-zero on error +*/ +static int read_physical_record(imgtool_stream *file_handle, int secnum, void *dest) +{ + int reply; + + /* seek to sector */ + reply = stream_seek(file_handle, secnum*512, SEEK_SET); + if (reply) + return 1; + /* read it */ + reply = stream_read(file_handle, dest, 512); + if (reply != 512) + return 1; + + return 0; +} + +#ifdef UNUSED_FUNCTION +/* + write_physical_record + + Write one 512-byte physical record to a disk image + + file_handle: imgtool file handle + secnum: logical sector address + src: pointer to source buffer + + Return non-zero on error +*/ +static int write_physical_record(imgtool_stream *file_handle, int secnum, const void *src) +{ + int reply; + + /* seek to sector */ + reply = stream_seek(file_handle, secnum*512, SEEK_SET); + if (reply) + return 1; + /* read it */ + reply = stream_write(file_handle, src, 512); + if (reply != 512) + return 1; + + return 0; +} +#endif + +/* + Search for a file name on a concept_image + + image (I): image reference + filename (I): name of the file to search + entry_index (O): index of file in disk catalog + + Return non-zero on error +*/ +static int get_catalog_entry(concept_image *image, const unsigned char *filename, int *entry_index) +{ + int filename_len = filename[0]; + int i; + + if (filename_len > 15) + /* file name is bad */ + return 1; + + for (i = 0; i < 77; i++) + { + if (!memcmp(filename, image->dev_dir.file_dir[i].filename, filename_len+1)) + { + /* file found */ + *entry_index = i; + return 0; + } + } + + /* file not found */ + return 1; +} + +/* + Open a file as a concept_image. +*/ +static imgtoolerr_t concept_image_init(imgtool_image *img, imgtool_stream *f) +{ + concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); + int reply; + int i; + unsigned totphysrecs; + + image->file_handle = f; + + /* read device directory */ + for (i=0; i<4; i++) + { + reply = read_physical_record(f, i+2, ((char *) & image->dev_dir)+i*512); + if (reply) + return IMGTOOLERR_READERROR; + } + + /* do primitive checks */ + totphysrecs = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) + - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block); + + if ((get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.first_block) != 0) + || (get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block) != 6) + || (totphysrecs < 6) /*|| (stream_size(f) != totphysrecs*512)*/ + || (image->dev_dir.vol_hdr.volname[0] > 7)) + { + return IMGTOOLERR_CORRUPTIMAGE; + } + + return IMGTOOLERR_SUCCESS; +} + +/* + close a concept_image +*/ +static void concept_image_exit(imgtool_image *img) +{ + /*concept_image *image = (concept_image *) imgtool_image_extra_bytes(img);*/ +} + +/* + get basic information on a concept_image + + Currently returns the volume name +*/ +static void concept_image_info(imgtool_image *img, char *string, size_t len) +{ + concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); + char vol_name[8]; + + memcpy(vol_name, image->dev_dir.vol_hdr.volname + 1, image->dev_dir.vol_hdr.volname[0]); + vol_name[image->dev_dir.vol_hdr.volname[0]] = 0; + + snprintf(string, len, "%s", vol_name); +} + +/* + Open the disk catalog for enumeration +*/ +static imgtoolerr_t concept_image_beginenum(imgtool_directory *enumeration, const char *path) +{ + concept_iterator *iter; + + iter = (concept_iterator *) imgtool_directory_extrabytes(enumeration); + iter->image = (concept_image *) imgtool_image_extra_bytes(imgtool_directory_image(enumeration)); + iter->index = 0; + return IMGTOOLERR_SUCCESS; +} + +/* + Enumerate disk catalog next entry +*/ +static imgtoolerr_t concept_image_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent) +{ + concept_iterator *iter = (concept_iterator *) imgtool_directory_extrabytes(enumeration); + + + ent->corrupt = 0; + ent->eof = 0; + + if ((iter->image->dev_dir.file_dir[iter->index].filename[0] == 0) || (iter->index > 77)) + { + ent->eof = 1; + } + else if (iter->image->dev_dir.file_dir[iter->index].filename[0] > 15) + { + ent->corrupt = 1; + } + else + { + int len = iter->image->dev_dir.file_dir[iter->index].filename[0]; + const char *type; + + if (len > ARRAY_LENGTH(ent->filename)) + len = ARRAY_LENGTH(ent->filename); + memcpy(ent->filename, iter->image->dev_dir.file_dir[iter->index].filename + 1, len); + ent->filename[len] = 0; + + /* parse flags */ + switch (get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].ftype) & 0xf) + { + case 0: + case 8: + type = "DIRHDR"; + break; + case 2: + type = "CODE"; + break; + case 3: + type = "TEXT"; + break; + case 5: + type = "DATA"; + break; + default: + type = "???"; + break; + } + snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%s", type); + + /* len in physrecs */ + ent->filesize = get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].next_block) + - get_UINT16xE(iter->image->dev_dir.vol_hdr.disk_flipped, iter->image->dev_dir.file_dir[iter->index].first_block); + + iter->index++; + } + + return (imgtoolerr_t)0; +} + +/* + Free enumerator +*/ +static void concept_image_closeenum(imgtool_directory *enumeration) +{ +} + +/* + Compute free space on disk image +*/ +static imgtoolerr_t concept_image_freespace(imgtool_partition *partition, UINT64 *size) +{ + imgtool_image *img = imgtool_partition_image(partition); + concept_image *image = (concept_image*) img; + int free_blocks; + int i; + + /* first get number of data blocks */ + free_blocks = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.last_block) + - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.vol_hdr.next_block); + + /* next substract length of each file */ + for (i=0; (image->dev_dir.file_dir[i].filename[0] != 0) && (i <= 77); i++) + { + free_blocks -= get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].next_block) + - get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[i].first_block); + } + + *size = free_blocks; + + return IMGTOOLERR_SUCCESS; +} + +/* + Extract a file from a concept_image. +*/ +static imgtoolerr_t concept_image_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf) +{ + imgtool_image *img = imgtool_partition_image(partition); + concept_image *image = (concept_image *) imgtool_image_extra_bytes(img); + size_t filename_len = strlen(filename); + unsigned char concept_fname[16]; + int catalog_index; + int i; + UINT8 buf[512]; + + if (filename_len > 15) + return IMGTOOLERR_BADFILENAME; + + concept_fname[0] = filename_len; + memcpy(concept_fname+1, filename, filename_len); + + if (get_catalog_entry(image, concept_fname, &catalog_index)) + return IMGTOOLERR_FILENOTFOUND; + + for (i = get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].first_block); + i < get_UINT16xE(image->dev_dir.vol_hdr.disk_flipped, image->dev_dir.file_dir[catalog_index].next_block); + i++) + { + if (read_physical_record(image->file_handle, i, buf)) + return IMGTOOLERR_READERROR; + + if (stream_write(destf, buf, 512) != 512) + return IMGTOOLERR_WRITEERROR; + } + + return (imgtoolerr_t)0; +} + +#if 0 +/* + Add a file to a concept_image. +*/ +static imgtoolerr_t concept_image_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *writeoptions) +{ + /* ... */ + + return 0; +} + +/* + Delete a file from a concept_image. +*/ +static imgtoolerr_t concept_image_deletefile(imgtool_partition *partition, const char *filename) +{ + /* ... */ + + return 0; +} + +/* + Create a blank concept_image. +*/ +static imgtoolerr_t concept_image_create(const imgtool_module *mod, imgtool_stream *f, option_resolution *createoptions) +{ + /* ... */ + + return 0; +} +#endif |