mirror of
https://github.com/holub/mame
synced 2025-05-04 21:43:05 +03:00
961 lines
27 KiB
C++
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, §or);
|
|
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;
|
|
}
|
|
}
|