mame/src/tools/imgtool/modules/vzdos.cpp

961 lines
27 KiB
C++

// license:GPL-2.0+
// copyright-holders:Dirk Best
/****************************************************************************
vzdos.c
Laser/VZ disk images
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "imgtool.h"
#include "formats/imageutl.h"
#include "formats/vt_dsk.h"
#include "iflopimg.h"
/*
sector format
| GAP1 | IDAM | GAP2 | DATA | CHECKSUM | ...
GAP1 = 80 80 80 80 80 00 6
IDAM = FE E7 18 C3 Track# Sector# Checksum-8 of prev. 2 bytes 7
GAP2 = 80 80 80 80 80 80 00 C3 18 E7 FE 11
DATA = 126 bytes actual data 126
= nextTrack# nextSector# 2
CHECKSUM = Checksum-16 of the previous 128 bytes 2
---
154 bytes
sectors 0 to 14 are used for the disk directory. sector 15 is used
as track map, with one bit for each sector used.
*/
#define DATA_SIZE (126)
#define SECTOR_SIZE (0x9b)
#define MAX_DIRENTS (15*8)
/* vzdos directry entry */
struct vzdos_dirent
{
char ftype;
char delimitor;
char fname[8];
UINT8 start_track;
UINT8 start_sector;
UINT16 start_address;
UINT16 end_address;
};
struct vz_iterator
{
int index;
int eof;
};
static const UINT8 sector_order[] =
{
0, 3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13
};
/*********************************************************************
Internal functions
*********************************************************************/
/* get length of filename without trailing spaces */
static int vzdos_get_fname_len(const char *fname)
{
int len;
for (len = 7; len > 0; len--)
if (fname[len] != 0x20)
break;
return len;
}
/* calculate checksum-16 of buffer */
static UINT16 chksum16(UINT8 *buffer, int len)
{
int i;
UINT16 sum = 0;
for (i = 0; i < len; i++)
sum += buffer[i];
return sum;
}
/* returns the offset where the actual sector data starts */
static imgtoolerr_t vzdos_get_data_start(imgtool::image *img, int track, int sector, int *start)
{
imgtoolerr_t ret;
UINT8 buffer[25]; /* enough to read the sector header */
ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, &buffer, sizeof(buffer));
if (ret) return ret;
/* search for start of data */
if (memcmp(buffer + 19, "\xC3\x18\xE7\xFE", 4) == 0)
*start = 23;
else if (memcmp(buffer + 20, "\xC3\x18\xE7\xFE", 4) == 0)
*start = 24;
else if (memcmp(buffer + 21, "\xC3\x18\xE7\xFE", 4) == 0)
*start = 25;
else
return IMGTOOLERR_CORRUPTIMAGE;
return IMGTOOLERR_SUCCESS;
}
/* return the actual data of a sector */
static imgtoolerr_t vzdos_read_sector_data(imgtool::image *img, int track, int sector, UINT8 *data)
{
int ret, data_start;
UINT8 buffer[DATA_SIZE + 4]; /* data + checksum */
ret = vzdos_get_data_start(img, track, sector, &data_start);
if (ret) return (imgtoolerr_t)ret;
ret = floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, &buffer, sizeof(buffer));
if (ret) return (imgtoolerr_t)ret;
/* verify sector checksums */
if (pick_integer_le(buffer, DATA_SIZE + 2, 2) != chksum16(buffer, DATA_SIZE + 2))
return IMGTOOLERR_CORRUPTFILE;
memcpy(data, &buffer, DATA_SIZE + 2);
return IMGTOOLERR_SUCCESS;
}
/* write data to sector */
static imgtoolerr_t vzdos_write_sector_data(imgtool::image *img, int track, int sector, UINT8 *data)
{
int ret, data_start;
UINT8 buffer[DATA_SIZE + 4]; /* data + checksum */
ret = vzdos_get_data_start(img, track, sector, &data_start);
if (ret) return (imgtoolerr_t)ret;
memcpy(buffer, data, DATA_SIZE + 2);
place_integer_le(buffer, DATA_SIZE + 2, 2, chksum16(data, DATA_SIZE + 2));
ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], data_start, buffer, sizeof(buffer), 0); /* TODO: pass ddam argument from imgtool */
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
/* write formatted empty sector */
static imgtoolerr_t vzdos_clear_sector(imgtool::image *img, int track, int sector)
{
UINT8 data[DATA_SIZE + 2];
memset(data, 0x00, sizeof(data));
return vzdos_write_sector_data(img, track, sector, data);
}
/* return a directory entry for an index */
static imgtoolerr_t vzdos_get_dirent(imgtool::image *img, int index, vzdos_dirent *ent)
{
int ret, entry;
UINT8 buffer[DATA_SIZE + 2];
ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer);
if (ret) return (imgtoolerr_t)ret;
entry = ((index % 8) * sizeof(vzdos_dirent));
memcpy(ent, &buffer[entry], 10);
ent->start_track = pick_integer_le(&buffer[entry], 10, 1);
ent->start_sector = pick_integer_le(&buffer[entry], 11, 1);
ent->start_address = pick_integer_le(&buffer[entry], 12, 2);
ent->end_address = pick_integer_le(&buffer[entry], 14, 2);
if (ent->ftype == 0x00)
return IMGTOOLERR_FILENOTFOUND;
/* check values */
if (ent->start_track > 39)
return IMGTOOLERR_CORRUPTFILE;
if (ent->start_sector > 15)
return IMGTOOLERR_CORRUPTFILE;
return IMGTOOLERR_SUCCESS;
}
/* save a directory entry to disk */
static imgtoolerr_t vzdos_set_dirent(imgtool::image *img, int index, vzdos_dirent ent)
{
int ret, entry;
UINT8 buffer[DATA_SIZE + 2];
/* read current sector with entries */
ret = vzdos_read_sector_data(img, 0, (int) index / 8, buffer);
if (ret) return (imgtoolerr_t)ret;
entry = ((index % 8) * sizeof(vzdos_dirent));
memcpy(&buffer[entry], &ent, 10);
place_integer_le(buffer, entry + 10, 1, ent.start_track);
place_integer_le(buffer, entry + 11, 1, ent.start_sector);
place_integer_le(buffer, entry + 12, 2, ent.start_address);
place_integer_le(buffer, entry + 14, 2, ent.end_address);
/* save new sector */
ret = vzdos_write_sector_data(img, 0, (int) index / 8, buffer);
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
/* clear a directory entry */
static imgtoolerr_t vzdos_clear_dirent(imgtool::image *img, int index)
{
int ret;
vzdos_dirent entry;
memset(&entry, 0x00, sizeof(vzdos_dirent));
ret = vzdos_set_dirent(img, index, entry);
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
/* search the index for a directory entry */
static imgtoolerr_t vzdos_searchentry(imgtool::image *image, const char *fname, int *entry) {
int i, len, ret;
vzdos_dirent ent;
char filename[9];
/* check for invalid filenames */
if (strlen(fname) > 8)
return IMGTOOLERR_BADFILENAME;
/* TODO: check for invalid characters */
*entry = -1;
for (i = 0; i < MAX_DIRENTS; i++) {
ret = vzdos_get_dirent(image, i, &ent);
if (ret) return (imgtoolerr_t)ret;
len = vzdos_get_fname_len(ent.fname) + 1;
if (strlen(fname) != len)
continue;
memset(filename, 0x00, sizeof(filename));
memcpy(filename, ent.fname, len);
if (!core_stricmp(fname, filename)) {
*entry = i;
break;
}
}
if (*entry == -1)
return IMGTOOLERR_FILENOTFOUND;
return IMGTOOLERR_SUCCESS;
}
/* return a directory entry for a filename */
static imgtoolerr_t vzdos_get_dirent_fname(imgtool::image *img, const char *fname, vzdos_dirent *ent)
{
int ret, index;
ret = vzdos_searchentry(img, fname, &index);
if (ret) return (imgtoolerr_t)ret;
ret = vzdos_get_dirent(img, index, ent);
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_toggle_trackmap(imgtool::image *img, int track, int sector, int clear)
{
int ret, value, bit;
UINT8 buffer[DATA_SIZE + 2];
/* get trackmap from image */
ret = vzdos_read_sector_data(img, 0, 15, buffer);
if (ret) return (imgtoolerr_t)ret;
value = (int) (floor(((double)track * 16 + sector) / 8) - 1);
bit = 0x01 << ((track * 16 + sector) % 8);
if (clear)
buffer[value-1] &= ~bit;
else
buffer[value-1] |= bit;
ret = vzdos_write_sector_data(img, 0, 15, buffer);
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
/* clear a trackmap entry */
static imgtoolerr_t vzdos_clear_trackmap(imgtool::image *img, int track, int sector)
{
return vzdos_toggle_trackmap(img, track, sector, 1);
}
/* enable a trackmap entry */
static imgtoolerr_t vzdos_set_trackmap(imgtool::image *img, int track, int sector)
{
return vzdos_toggle_trackmap(img, track, sector, 0);
}
/* return the status of a trackmap entry */
static imgtoolerr_t vzdos_get_trackmap(imgtool::image *img, int track, int sector, int *used)
{
int ret, value, bit;
UINT8 buffer[DATA_SIZE + 2];
/* get trackmap from image */
ret = vzdos_read_sector_data(img, 0, 15, buffer);
if (ret) return (imgtoolerr_t)ret;
value = (int) (floor(((double)track * 16 + sector) / 8) - 1);
bit = 0x01 << ((track * 16 + sector) % 8);
if (buffer[value-1] & bit)
*used = 1;
else
*used = 0;
return IMGTOOLERR_SUCCESS;
}
/* return the next free sector */
static imgtoolerr_t vzdos_free_trackmap(imgtool::image *img, int *track, int *sector)
{
int ret, used = 0;
for (*track = 1; *track < 40; (*track)++) {
for (*sector = 0; *sector < 16; (*sector)++) {
ret = vzdos_get_trackmap(img, *track, *sector, &used);
if (ret) return (imgtoolerr_t)ret;
if (!used) return IMGTOOLERR_SUCCESS;
}
}
return IMGTOOLERR_NOSPACE;
}
static imgtoolerr_t vzdos_write_formatted_sector(imgtool::image *img, int track, int sector)
{
int ret;
UINT8 sector_data[DATA_SIZE + 4 + 24];
static const UINT8 sector_header[24] = {
0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFE, 0xE7,
0x18, 0xC3, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x00, 0xC3, 0x18, 0xE7, 0xFE
};
memset(sector_data, 0x00, sizeof(sector_data));
memcpy(sector_data, sector_header, sizeof(sector_header));
sector_data[10] = (UINT8) track; /* current track */
sector_data[11] = (UINT8) sector; /* current sector */
sector_data[12] = (UINT8) track + sector; /* checksum-8 */
ret = floppy_write_sector(imgtool_floppy(img), 0, track, sector_order[sector], 0, sector_data, sizeof(sector_data), 0); /* TODO: pass ddam argument from imgtool */
if (ret) return (imgtoolerr_t)ret;
return IMGTOOLERR_SUCCESS;
}
/*********************************************************************
Imgtool module code
*********************************************************************/
static imgtoolerr_t vzdos_diskimage_beginenum(imgtool_directory *enumeration, const char *path)
{
vz_iterator *iter;
iter = (vz_iterator *) imgtool_directory_extrabytes(enumeration);
if (!iter) return IMGTOOLERR_OUTOFMEMORY;
iter->index = 1;
iter->eof = 0;
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_diskimage_nextenum(imgtool_directory *enumeration, imgtool_dirent *ent)
{
vz_iterator *iter = (vz_iterator *) imgtool_directory_extrabytes(enumeration);
if (iter->eof == 1 || iter->index > MAX_DIRENTS) {
ent->eof = 1;
} else {
const char *type;
int ret, len;
vzdos_dirent dirent;
ret = vzdos_get_dirent(imgtool_directory_image(enumeration), iter->index - 1, &dirent);
if (ret == IMGTOOLERR_FILENOTFOUND)
{
iter->eof = 1;
ent->eof = 1;
return IMGTOOLERR_SUCCESS;
}
if (ret == IMGTOOLERR_CORRUPTFILE)
ent->corrupt = 1;
/* kill trailing spaces */
for (len = 7; len > 0; len--) {
if (dirent.fname[len] != 0x20) {
break;
}
}
memcpy(ent->filename, &dirent.fname, len + 1);
ent->filesize = dirent.end_address - dirent.start_address;
switch (dirent.ftype)
{
case 0x01: type = "Deleted"; break;
case 'T': type = "Basic"; break;
case 'B': type = "Binary"; break;
case 'D': type = "Data"; break;
case 'F': type = "Quickwrite"; break;
case 'A': type = "Assembler"; break;
case 'S': type = "Diskops"; break;
case 'W': type = "Wordpro"; break;
default: type = "Unknown";
}
snprintf(ent->attr, ARRAY_LENGTH(ent->attr), "%s", type);
iter->index++;
}
return IMGTOOLERR_SUCCESS;
}
/* TRK 0 sector 15 is used to hold the track map of the disk with one bit
corresponding to a sector used. */
static imgtoolerr_t vzdos_diskimage_freespace(imgtool_partition *partition, UINT64 *size)
{
imgtoolerr_t ret;
int i;
imgtool::image *image = imgtool_partition_image(partition);
UINT8 c, v, buffer[DATA_SIZE + 2];
*size = 0;
ret = vzdos_read_sector_data(image, 0, 15, buffer);
if (ret) return ret;
for (i = 0; i < DATA_SIZE; i++) {
v = buffer[i];
for (c = 0; v; c++) {
v &= v - 1;
}
*size += c * DATA_SIZE;
}
*size = (DATA_SIZE * 16 * 39) - *size;
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_diskimage_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf)
{
imgtoolerr_t ret;
imgtool::image *image = imgtool_partition_image(partition);
int filesize, track, sector;
vzdos_dirent ent;
UINT8 buffer[DATA_SIZE + 2];
ret = vzdos_get_dirent_fname(image, filename, &ent);
if (ret) return ret;
filesize = ent.end_address - ent.start_address;
track = ent.start_track;
sector = ent.start_sector;
while (filesize > 0) {
int towrite;
ret = vzdos_read_sector_data(image, track, sector, buffer);
if (ret) return ret;
/* detect sectors pointing to themselfs */
if ((track == (int)pick_integer_le(buffer, DATA_SIZE, 1)) && (sector == (int)pick_integer_le(buffer, DATA_SIZE + 1, 1)))
return IMGTOOLERR_CORRUPTIMAGE;
/* load next track and sector values */
track = pick_integer_le(buffer, DATA_SIZE, 1);
sector = pick_integer_le(buffer, DATA_SIZE + 1, 1);
/* track 0 is invalid */
if ((track == 0) && (filesize > DATA_SIZE))
return IMGTOOLERR_CORRUPTIMAGE;
/* write either DATA_SIZE or the remaining bytes */
towrite = filesize > DATA_SIZE ? DATA_SIZE : filesize;
if (stream_write(destf, buffer, towrite) != towrite)
return IMGTOOLERR_WRITEERROR;
filesize -= DATA_SIZE;
}
return IMGTOOLERR_SUCCESS;
}
/* deletes directory entry, clears trackmap entries and sectors */
static imgtoolerr_t vzdos_diskimage_deletefile(imgtool_partition *partition, const char *fname)
{
imgtoolerr_t ret;
imgtool::image *img = imgtool_partition_image(partition);
int index, filesize, track, sector, next_track, next_sector;
vzdos_dirent entry, next_entry;
UINT8 buffer[DATA_SIZE + 2];
ret = vzdos_get_dirent_fname(img, fname, &entry);
if (ret) return ret;
ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, entry.start_track, sector_order[entry.start_sector], 24, &buffer, DATA_SIZE + 2);
if (ret) return ret;
filesize = entry.end_address - entry.start_address;
track = entry.start_track;
sector = entry.start_sector;
/* delete directory entry */
ret = vzdos_searchentry(img, fname, &index);
if (ret) return ret;
ret = vzdos_get_dirent(img, index + 1, &next_entry);
if (ret == IMGTOOLERR_FILENOTFOUND) {
/* we are the last directory entry, just delete it */
ret = vzdos_clear_dirent(img, index);
if (ret) return ret;
} else if (ret) {
/* an error occurred */
return ret;
} else {
ret = vzdos_set_dirent(img, index++, next_entry);
if (ret) return ret;
while ((ret = vzdos_get_dirent(img, index + 1, &next_entry)) != IMGTOOLERR_FILENOTFOUND) {
if (ret) return ret;
ret = vzdos_set_dirent(img, index++, next_entry);
if (ret) return ret;
}
ret = vzdos_clear_dirent(img, index);
if (ret) return ret;
}
/* clear sectors and trackmap entries */
while (filesize > 0) {
filesize -= DATA_SIZE;
/* clear trackmap entry */
ret = vzdos_clear_trackmap(img, track, sector);
if (ret) return ret;
/* load next track and sector values */
next_track = pick_integer_le(buffer, DATA_SIZE, 1);
next_sector = pick_integer_le(buffer, DATA_SIZE + 1, 1);
/* overwrite sector with default values */
ret = vzdos_clear_sector(img, track, sector);
if (ret) return ret;
/* read next sector */
track = next_track;
sector = next_sector;
if (filesize > 0) {
ret = (imgtoolerr_t)floppy_read_sector(imgtool_floppy(img), 0, track, sector_order[sector], 24, &buffer, DATA_SIZE + 2);
if (ret) return ret;
}
}
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_writefile(imgtool_partition *partition, int offset, imgtool_stream *sourcef, vzdos_dirent *entry)
{
imgtoolerr_t ret;
imgtool::image *img = imgtool_partition_image(partition);
int index, track, sector, toread, next_track, next_sector;
vzdos_dirent temp_entry;
UINT64 filesize = 0, freespace = 0;
UINT8 buffer[DATA_SIZE + 2];
char filename[9];
/* is the image writeable? */
if (floppy_is_read_only(imgtool_floppy(img)))
return IMGTOOLERR_READONLY;
/* check for already existing filename -> overwrite */
strcpy(filename, entry->fname);
filename[vzdos_get_fname_len(entry->fname) + 1] = 0x00;
ret = vzdos_get_dirent_fname(img, filename, &temp_entry);
if (!ret) {
/* file already exists, delete it */
ret = vzdos_diskimage_deletefile(partition, filename);
if (ret) return ret;
} else if (ret != IMGTOOLERR_FILENOTFOUND) {
/* another error occurred, return it */
return ret;
}
ret = (imgtoolerr_t)stream_seek(sourcef, offset, SEEK_SET);
if (ret) return ret;
/* check if there is enough space */
filesize = stream_size(sourcef) - offset;
ret = vzdos_diskimage_freespace(partition, &freespace);
if (ret) return ret;
if (filesize > freespace)
return IMGTOOLERR_NOSPACE;
/* get next free track and sector */
ret = vzdos_free_trackmap(img, &track, &sector);
if (ret) return ret;
entry->end_address = entry->start_address + (unsigned int) filesize;
entry->start_track = track;
entry->start_sector = sector;
/* search for next free directory entry */
for (index = 0; index < MAX_DIRENTS; index++) {
ret = vzdos_get_dirent(img, index, &temp_entry);
if (ret == IMGTOOLERR_FILENOTFOUND)
break;
else if (ret)
return (ret);
}
/* write directory entry to disk */
ret = vzdos_set_dirent(img, index, *entry);
if (ret) return ret;
next_track = 0;
next_sector = 0;
/* write data to disk */
while (filesize > 0) {
toread = filesize > DATA_SIZE ? DATA_SIZE : filesize;
stream_read(sourcef, buffer, toread);
filesize -= toread;
/* mark sector as used */
ret = vzdos_set_trackmap(img, track, sector);
if (ret) return ret;
/* get track and sector for next sector */
if (filesize > 0) {
ret = vzdos_free_trackmap(img, &next_track, &next_sector);
if (ret) return ret;
} else {
next_track = 0;
next_sector = 0;
}
buffer[DATA_SIZE] = next_track;
buffer[DATA_SIZE + 1] = next_sector;
/* write sector to disk */
ret = vzdos_write_sector_data(img, track, sector, buffer);
if (ret) return ret;
track = next_track;
sector = next_sector;
}
return IMGTOOLERR_SUCCESS;
}
/* create a new file or overwrite a file */
static imgtoolerr_t vzdos_diskimage_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, util::option_resolution *opts)
{
imgtoolerr_t ret;
int ftype;
vzdos_dirent entry;
/* TODO: check for leading spaces and strip */
if (strlen(filename) > 8 || strlen(filename) < 1)
return IMGTOOLERR_BADFILENAME;
/* prepare directory entry */
ftype = opts->lookup_int('T');
switch (ftype) {
case 0:
entry.ftype = 'T';
entry.start_address = 31465;
break;
case 1:
entry.ftype = 'B';
entry.start_address = 31465; /* ??? */
break;
case 2:
entry.ftype = 'D';
entry.start_address = 31465; /* ??? */
break;
default:
break;
}
entry.delimitor = ':';
memset(&entry.fname, 0x20, 8); /* pad with spaces */
memcpy(&entry.fname, filename, strlen(filename));
/* write file to disk */
ret = vzdos_writefile(partition, 0, sourcef, &entry);
if (ret) return ret;
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_diskimage_suggesttransfer(imgtool_partition *partition, const char *fname, imgtool_transfer_suggestion *suggestions, size_t suggestions_length)
{
imgtoolerr_t ret;
imgtool::image *image = imgtool_partition_image(partition);
vzdos_dirent entry;
if (fname) {
ret = vzdos_get_dirent_fname(image, fname, &entry);
if (ret) return ret;
switch (entry.ftype) {
case 'B':
suggestions[0].viability = SUGGESTION_RECOMMENDED;
suggestions[0].filter = filter_vzsnapshot_getinfo;
suggestions[0].description = "VZ Snapshot";
suggestions[1].viability = SUGGESTION_POSSIBLE;
suggestions[1].filter = NULL;
suggestions[1].description = "Raw";
break;
case 'T':
suggestions[0].viability = SUGGESTION_RECOMMENDED;
suggestions[0].filter = filter_vzsnapshot_getinfo;
suggestions[0].description = "VZ Snapshot";
suggestions[1].viability = SUGGESTION_POSSIBLE;
suggestions[1].filter = NULL;
suggestions[1].description = "Raw";
suggestions[2].viability = SUGGESTION_POSSIBLE;
suggestions[2].filter = filter_vzbas_getinfo;
suggestions[2].description = "Tokenized Basic";
break;
default:
suggestions[0].viability = SUGGESTION_RECOMMENDED;
suggestions[0].filter = NULL;
suggestions[0].description = "Raw";
}
} else {
suggestions[0].viability = SUGGESTION_RECOMMENDED;
suggestions[0].filter = NULL;
suggestions[0].description = "Raw";
suggestions[1].viability = SUGGESTION_POSSIBLE;
suggestions[1].filter = filter_vzsnapshot_getinfo;
suggestions[1].description = "VZ Snapshot";
}
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzdos_diskimage_create(imgtool::image *img, imgtool_stream *stream, util::option_resolution *opts)
{
imgtoolerr_t ret;
int track, sector;
for (track = 0; track < 40; track++) {
for (sector = 0; sector < 16; sector++) {
ret = vzdos_write_formatted_sector(img, track, sector);
if (ret) return ret;
}
}
return IMGTOOLERR_SUCCESS;
}
/*********************************************************************
Imgtool vz filter code
*********************************************************************/
static imgtoolerr_t vzsnapshot_readfile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf)
{
imgtoolerr_t ret;
imgtool::image *image = imgtool_partition_image(partition);
vzdos_dirent entry;
UINT8 header[24];
/* get directory entry from disk */
ret = vzdos_get_dirent_fname(image, filename, &entry);
if (ret) return ret;
/* prepare header */
header[0] = 'V';
header[1] = 'Z';
header[2] = 'F';
switch (entry.ftype) {
case 'B':
header[3] = '1';
header[21] = 0xF1;
break;
case 'T':
header[3] = '0';
header[21] = 0xF0;
break;
default:
memset(header, 0x00, 4);
header[21] = 0x00;
}
memset(header + 4, 0x00, 17);
memcpy(header + 4, entry.fname, vzdos_get_fname_len(entry.fname) + 1);
place_integer_le(header, 22, 2, entry.start_address);
/* write header to file */
stream_write(destf, header, sizeof(header));
/* write data to file */
ret = vzdos_diskimage_readfile(partition, filename, "", destf);
if (ret) return ret;
return IMGTOOLERR_SUCCESS;
}
static imgtoolerr_t vzsnapshot_writefile(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, util::option_resolution *opts)
{
imgtoolerr_t ret;
int fnameopt;
vzdos_dirent entry;
UINT8 header[24];
/* get header infos from file */
stream_read(sourcef, header, sizeof(header));
/* prepare directory entry */
entry.ftype = header[21] == 0xF1 ? 'B' : 'T';
entry.delimitor = ':';
entry.start_address = pick_integer_le(header, 22, 2);
/* filename from header or directly? */
fnameopt = opts->lookup_int('F');
if (fnameopt == 0) {
memcpy(&entry.fname, &header[4], 8);
} else {
/* TODO: check for leading spaces and strip */
if (strlen(filename) > 8 || strlen(filename) < 1)
return IMGTOOLERR_BADFILENAME;
memcpy(&entry.fname, filename, strlen(filename) - 3);
}
/* write file to disk */
ret = vzdos_writefile(partition, 24, sourcef, &entry);
if (ret) return ret;
return IMGTOOLERR_SUCCESS;
}
void filter_vzsnapshot_getinfo(UINT32 state, union filterinfo *info)
{
switch(state)
{
case FILTINFO_STR_NAME: info->s = "vzsnapshot"; break;
case FILTINFO_STR_HUMANNAME: info->s = "VZ Snapshot"; break;
case FILTINFO_STR_EXTENSION: info->s = "vz"; break;
case FILTINFO_PTR_READFILE: info->read_file = vzsnapshot_readfile; break;
case FILTINFO_PTR_WRITEFILE: info->write_file = vzsnapshot_writefile; break;
}
}
/*********************************************************************
Imgtool module declaration
*********************************************************************/
OPTION_GUIDE_START(vzdos_writefile_optionguide)
OPTION_ENUM_START( 'T', "ftype", "File type" )
OPTION_ENUM( 0, "basic", "Basic" )
OPTION_ENUM( 1, "binary", "Binary" )
OPTION_ENUM( 2, "data", "Data" )
OPTION_ENUM_END
OPTION_ENUM_START( 'F', "fname", "Filename" )
OPTION_ENUM( 0, "intern", "Filename from VZ-Header" )
OPTION_ENUM( 1, "extern", "Actual filename" )
OPTION_ENUM_END
OPTION_GUIDE_END
/*
T Basic Editor File
B Binary File
D Sequential Access Program Data File
F Quickwrite Document
A Russell Harrison's Edit Ass. File
S Dave Mitchell/Mark Hardwood Edit Ass. File Start Addr A280H
S Quickwrite/Diskops System File/Label Except Above
W Edit Ass. with Diskops File Start Addr A813H
W E & F Word Pro with Patch 3.3 File End Addr D000H
W Russell Harrison Word Pro File Except above two
*/
void vzdos_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_PREFER_UCASE: info->i = 1; break;
case IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES: info->i = sizeof(vz_iterator); break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "vzdos"); break;
case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "VZ-DOS format"); break;
case IMGTOOLINFO_STR_FILE: strcpy(info->s = imgtool_temp_str(), __FILE__); break;
case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), "T[0]-2;F[0]-1"); break;
case IMGTOOLINFO_STR_EOLN: info->s = NULL; break;
/* --- the following bits of info are returned as pointers to data or functions --- */
case IMGTOOLINFO_PTR_MAKE_CLASS: info->make_class = imgtool_floppy_make_class; break;
case IMGTOOLINFO_PTR_OPEN: info->open = NULL; break;
case IMGTOOLINFO_PTR_BEGIN_ENUM: info->begin_enum = vzdos_diskimage_beginenum; break;
case IMGTOOLINFO_PTR_NEXT_ENUM: info->next_enum = vzdos_diskimage_nextenum; break;
case IMGTOOLINFO_PTR_FREE_SPACE: info->free_space = vzdos_diskimage_freespace; break;
case IMGTOOLINFO_PTR_READ_FILE: info->read_file = vzdos_diskimage_readfile; break;
case IMGTOOLINFO_PTR_WRITE_FILE: info->write_file = vzdos_diskimage_writefile; break;
case IMGTOOLINFO_PTR_DELETE_FILE: info->delete_file = vzdos_diskimage_deletefile; break;
case IMGTOOLINFO_PTR_FLOPPY_CREATE: info->create = vzdos_diskimage_create; break;
case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE: info->writefile_optguide = &vzdos_writefile_optionguide; break;
case IMGTOOLINFO_PTR_SUGGEST_TRANSFER: info->suggest_transfer = vzdos_diskimage_suggesttransfer; break;
case IMGTOOLINFO_PTR_FLOPPY_FORMAT: info->p = (void *) floppyoptions_vz; break;
}
}