summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/imgtool/modules/concept.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/imgtool/modules/concept.c')
-rw-r--r--src/tools/imgtool/modules/concept.c492
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