diff options
Diffstat (limited to 'trunk/src/lib/formats/apridisk.c')
-rw-r--r-- | trunk/src/lib/formats/apridisk.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/apridisk.c b/trunk/src/lib/formats/apridisk.c new file mode 100644 index 00000000000..1998a72acfc --- /dev/null +++ b/trunk/src/lib/formats/apridisk.c @@ -0,0 +1,226 @@ +/*************************************************************************** + + APRIDISK disk image format + +***************************************************************************/ + +#include "apridisk.h" +#include "imageutl.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define APR_HEADER_SIZE 128 + +/* sector types */ +#define APR_DELETED 0xe31d0000 +#define APR_MAGIC 0xe31d0001 +#define APR_COMMENT 0xe31d0002 +#define APR_CREATOR 0xe31d0003 + +/* compression type */ +#define APR_UNCOMPRESSED 0x9e90 +#define APR_COMPRESSED 0x3e5a + +static const char *apr_magic = "ACT Apricot disk image\x1a\x04"; + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct apr_sector +{ + int head; + int track; + int sector; + UINT8 data[512]; +}; + +struct apr_tag +{ + int heads; + int tracks; + int sectors_per_track; + struct apr_sector sectors[2880]; + char *comment; +}; + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/* sector format: + * + * 00-03: sector type + * 04-05: compression type + * 06-07: header size + * 08-11: data size + * 12-13: track + * 14: head + * 15: sector + */ + +static floperr_t apr_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) +{ + struct apr_tag *tag = (apr_tag *)floppy_tag(floppy); +// printf("apr_read_sector %d %d %d\n", head, track, sector); + memcpy(buffer, tag->sectors[head * track * sector].data, buflen); + return FLOPPY_ERROR_SUCCESS; +} + +static floperr_t apr_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) +{ + struct apr_tag *tag = (apr_tag *)floppy_tag(floppy); +// printf("apr_read_indexed_sector %d %d %d\n", head, track, sector); + memcpy(buffer, tag->sectors[head * track * sector].data, buflen); + return FLOPPY_ERROR_SUCCESS; +} + +/* sector length is always 512 byte */ +static floperr_t apr_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length) +{ + *sector_length = 512; + return FLOPPY_ERROR_SUCCESS; +} + +static int apr_get_heads_per_disk(floppy_image_legacy *floppy) +{ + struct apr_tag *tag = (apr_tag *)floppy_tag(floppy); + return tag->heads; +} + +static int apr_get_tracks_per_disk(floppy_image_legacy *floppy) +{ + struct apr_tag *tag = (apr_tag *)floppy_tag(floppy); + return tag->tracks; +} + +static floperr_t apr_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags) +{ + struct apr_tag *tag = (apr_tag *)floppy_tag(floppy); + +// printf("apr_get_indexed_sector_info %d %d %d\n", head, track, sector_index); + + /* sanity checks */ + if (head < 0 || head > (tag->heads - 1)) return FLOPPY_ERROR_SEEKERROR; + if (track < 0 || track > (tag->tracks - 1)) return FLOPPY_ERROR_SEEKERROR; + if (sector_index < 0 || sector_index > (tag->sectors_per_track - 1)) return FLOPPY_ERROR_SEEKERROR; + + if (cylinder) *cylinder = tag->sectors[head * track * sector_index].track; + if (side) *side = tag->sectors[head * track * sector_index].head; + if (sector) *sector = tag->sectors[head * track * sector_index].sector; + if (sector_length) *sector_length = 512; + + return FLOPPY_ERROR_SUCCESS; +} + +FLOPPY_IDENTIFY( apridisk_identify ) +{ + UINT8 header[APR_HEADER_SIZE]; + + /* get header */ + floppy_image_read(floppy, &header, 0, sizeof(header)); + + /* look for the magic string */ + if (memcmp(header, apr_magic, sizeof(*apr_magic)) == 0) + *vote = 100; + else + *vote = 0; + + return FLOPPY_ERROR_SUCCESS; +} + +FLOPPY_CONSTRUCT( apridisk_construct ) +{ + struct FloppyCallbacks *callbacks; + struct apr_tag *tag; + + int cur_sector = 0; + UINT8 sector_header[16]; + UINT64 pos = 128; + UINT32 type; + + tag = (apr_tag *)floppy_create_tag(floppy, sizeof(struct apr_tag)); + + if (!tag) + return FLOPPY_ERROR_OUTOFMEMORY; + + tag->heads = 0; + tag->tracks = 0; + tag->sectors_per_track = 0; + + floppy_image_read(floppy, §or_header, pos, 16); + type = pick_integer_le(§or_header, 0, 4); + + while (type == APR_DELETED || type == APR_MAGIC || type == APR_COMMENT || type == APR_CREATOR) + { + UINT16 compression = pick_integer_le(§or_header, 4, 2); + UINT16 header_size = pick_integer_le(§or_header, 6, 2); + UINT32 data_size = pick_integer_le(§or_header, 8, 4); + + tag->sectors[cur_sector].head = pick_integer_le(§or_header, 12, 1); + tag->sectors[cur_sector].sector = pick_integer_le(§or_header, 13, 1); + tag->sectors[cur_sector].track = pick_integer_le(§or_header, 14, 1); + + pos += header_size; + + if (type == APR_MAGIC) + { + if (compression == APR_UNCOMPRESSED) + { + floppy_image_read(floppy, &tag->sectors[cur_sector].data, pos, data_size); + + } + else if (compression == APR_COMPRESSED) + { + UINT8 *buffer = (UINT8 *)osd_malloc(data_size * sizeof(UINT8)); + UINT16 length; + UINT8 value; + + floppy_image_read(floppy, buffer, pos, data_size); + + length = pick_integer_le(buffer, 0, 2); + value = pick_integer_le(buffer, 2, 1); + + osd_free(buffer); + + /* not sure if this is possible */ + if (length != 512) { + printf("Compression unsupported"); + exit(-1); + } + + memset(&tag->sectors[cur_sector].data, value, length); + } + else + return FLOPPY_ERROR_INVALIDIMAGE; + + tag->heads = MAX(tag->sectors[cur_sector].head, tag->heads); + tag->tracks = MAX(tag->sectors[cur_sector].track, tag->tracks); + tag->sectors_per_track = MAX(tag->sectors[cur_sector].sector, tag->sectors_per_track); + } + + /* seek to next sector */ + pos += data_size; + cur_sector++; + + floppy_image_read(floppy, §or_header, pos, 16); + type = pick_integer_le(§or_header, 0, 4); + } + + tag->heads++; + tag->tracks++; + + callbacks = floppy_callbacks(floppy); + callbacks->read_sector = apr_read_sector; + callbacks->read_indexed_sector = apr_read_indexed_sector; + callbacks->get_sector_length = apr_get_sector_length; + callbacks->get_heads_per_disk = apr_get_heads_per_disk; + callbacks->get_tracks_per_disk = apr_get_tracks_per_disk; + callbacks->get_indexed_sector_info = apr_get_indexed_sector_info; + + return FLOPPY_ERROR_SUCCESS; +} |