mame/src/lib/formats/cqm_dsk.c
2011-07-20 09:35:15 +00:00

229 lines
5.4 KiB
C

/*********************************************************************
formats/cqm_dsk.c
CopyQM disk images
*********************************************************************/
#include <string.h>
#include "flopimg.h"
#define CQM_HEADER_SIZE 133
struct cqmdsk_tag
{
int heads;
int tracks;
int sector_size;
int sector_per_track;
int sector_base;
int interleave;
int skew;
UINT8* buf;
UINT64 track_offsets[84*2]; /* offset within data for each track */
};
static struct cqmdsk_tag *get_tag(floppy_image_legacy *floppy)
{
struct cqmdsk_tag *tag;
tag = (cqmdsk_tag *)floppy_tag(floppy );
return tag;
}
FLOPPY_IDENTIFY( cqm_dsk_identify )
{
UINT8 header[2];
floppy_image_read(floppy, header, 0, 2);
if (header[0]=='C' && header[1]=='Q') {
*vote = 100;
} else {
*vote = 0;
}
return FLOPPY_ERROR_SUCCESS;
}
static int cqm_get_heads_per_disk(floppy_image_legacy *floppy)
{
return get_tag(floppy)->heads;
}
static int cqm_get_tracks_per_disk(floppy_image_legacy *floppy)
{
return get_tag(floppy)->tracks;
}
static UINT64 cqm_get_track_offset(floppy_image_legacy *floppy, int head, int track)
{
return get_tag(floppy)->track_offsets[(track<<1) + head];
}
static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, UINT64 *offset)
{
UINT64 pos = 0;
UINT8 data;
INT16 len;
int s;
if ((head < 0) || (head >= get_tag(floppy)->heads) || (track < 0) || (track >= get_tag(floppy)->tracks)
|| (sector < 0) )
return FLOPPY_ERROR_SEEKERROR;
pos = cqm_get_track_offset(floppy,head,track);
s = 0;
do {
floppy_image_read(floppy, &len, pos, 2);
pos+=2;
if(len<0) {
floppy_image_read(floppy, &data, pos, 1);
memset(get_tag(floppy)->buf + s,data, -len);
pos++;
s += -len;
} else {
floppy_image_read(floppy, get_tag(floppy)->buf + s, pos, len);
pos+=len;
s += len;
}
} while(s<get_tag(floppy)->sector_size*get_tag(floppy)->sector_per_track);
if (offset)
*offset = sector * get_tag(floppy)->sector_size;
return FLOPPY_ERROR_SUCCESS;
}
static floperr_t internal_cqm_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen)
{
UINT64 offset;
floperr_t err;
// take sector offset
err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
if (err)
return err;
memcpy(buffer,get_tag(floppy)->buf+offset,buflen);
return FLOPPY_ERROR_SUCCESS;
}
static floperr_t cqm_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
{
return internal_cqm_read_sector(floppy, head, track, sector, FALSE, buffer, buflen);
}
static floperr_t cqm_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
{
return internal_cqm_read_sector(floppy, head, track, sector, TRUE, buffer, buflen);
}
static floperr_t cqm_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length)
{
floperr_t err;
err = get_offset(floppy, head, track, sector, FALSE, NULL);
if (err)
return err;
if (sector_length) {
*sector_length = get_tag(floppy)->sector_size;
}
return FLOPPY_ERROR_SUCCESS;
}
static floperr_t cqm_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)
{
if (sector_index >= get_tag(floppy)->sector_per_track) return FLOPPY_ERROR_SEEKERROR;
if (cylinder) {
*cylinder = track;
}
if (side) {
*side = head;
}
if (sector) {
*sector = get_tag(floppy)->sector_base + sector_index;
}
if (sector_length) {
*sector_length = get_tag(floppy)->sector_size;
}
if (flags)
*flags = 0;
return FLOPPY_ERROR_SUCCESS;
}
FLOPPY_CONSTRUCT( cqm_dsk_construct )
{
struct FloppyCallbacks *callbacks;
struct cqmdsk_tag *tag;
UINT8 header[CQM_HEADER_SIZE];
UINT64 pos = 0;
INT16 len;
int head;
int track;
int s;
if(params)
{
// create
return FLOPPY_ERROR_UNSUPPORTED;
}
tag = (struct cqmdsk_tag *) floppy_create_tag(floppy, sizeof(struct cqmdsk_tag));
if (!tag)
return FLOPPY_ERROR_OUTOFMEMORY;
floppy_image_read(floppy, header, 0, CQM_HEADER_SIZE);
tag->sector_size = (header[0x04] << 8) + header[0x03];
tag->sector_per_track = header[0x10];
tag->heads = header[0x12];
tag->tracks = header[0x5b];
tag->sector_base = header[0x71] + 1;
tag->interleave = header[0x74];
tag->skew = header[0x75];
// header + comment size to position on first data block
pos = CQM_HEADER_SIZE + (header[0x70] << 8) + header[0x6f];
track = 0;
head = 0;
tag->buf = (UINT8*)malloc(tag->sector_size*tag->sector_per_track);
do {
tag->track_offsets[(track<<1) + head] = pos;
s = 0;
do {
floppy_image_read(floppy, &len, pos, 2);
pos+=2;
if(len<0) {
pos++;
s += -len;
} else {
pos+=len;
s += len;
}
} while(s<tag->sector_size*tag->sector_per_track);
if(head ==0 && tag->heads > 1) {
head = 1;
} else {
head = 0;
track++;
}
} while(pos < floppy_image_size(floppy));
callbacks = floppy_callbacks(floppy);
callbacks->read_sector = cqm_read_sector;
callbacks->read_indexed_sector = cqm_read_indexed_sector;
callbacks->get_sector_length = cqm_get_sector_length;
callbacks->get_heads_per_disk = cqm_get_heads_per_disk;
callbacks->get_tracks_per_disk = cqm_get_tracks_per_disk;
callbacks->get_indexed_sector_info = cqm_get_indexed_sector_info;
return FLOPPY_ERROR_SUCCESS;
}