mirror of
https://github.com/holub/mame
synced 2025-06-30 07:58:56 +03:00
imgtool, hp9845_tape format: write&del done, brief info added at the
start of file.
This commit is contained in:
parent
e39c05c165
commit
e25e1b84b0
@ -747,10 +747,10 @@ static void listoptions(const util::option_guide &opt_guide, const char *opt_spe
|
|||||||
fprintf(stdout, "Option Allowed values Description\n");
|
fprintf(stdout, "Option Allowed values Description\n");
|
||||||
fprintf(stdout, "---------------- ------------------------------ -----------\n");
|
fprintf(stdout, "---------------- ------------------------------ -----------\n");
|
||||||
|
|
||||||
std::stringstream description_buffer;
|
|
||||||
for (auto iter = resolution.entries_begin(); iter != resolution.entries_end(); iter++)
|
for (auto iter = resolution.entries_begin(); iter != resolution.entries_end(); iter++)
|
||||||
{
|
{
|
||||||
const util::option_resolution::entry &entry = *iter;
|
const util::option_resolution::entry &entry = *iter;
|
||||||
|
std::stringstream description_buffer;
|
||||||
|
|
||||||
std::string opt_name = string_format("--%s", entry.identifier());
|
std::string opt_name = string_format("--%s", entry.identifier());
|
||||||
const char *opt_desc = entry.display_name();
|
const char *opt_desc = entry.display_name();
|
||||||
|
@ -6,6 +6,61 @@
|
|||||||
|
|
||||||
HP-9845 tape format
|
HP-9845 tape format
|
||||||
|
|
||||||
|
This imgtool module manipulates HTI files. These are image files
|
||||||
|
of the DC-100 tape cartridges that are simulated for the HP9845B
|
||||||
|
driver.
|
||||||
|
HP9845 filesystem for tapes has the following features:
|
||||||
|
* File names are 1 to 6 characters long.
|
||||||
|
* Case is significant in file names.
|
||||||
|
* There is no file "extension", file type is encoded separately
|
||||||
|
in file metadata.
|
||||||
|
* There are 8 file types. File type is encoded in 5 bits.
|
||||||
|
Only 8 out of the 32 possible values are valid.
|
||||||
|
* This module handles the file type as a fake file extension.
|
||||||
|
For example, a file named "TEST" having DATA type is get/put/shown
|
||||||
|
as "TEST.DATA".
|
||||||
|
* File type is deduced from host file extension when putting files
|
||||||
|
into image. File type can be overridden by the "ftype" option.
|
||||||
|
* Files are always stored in units of 256-byte physical records.
|
||||||
|
* An important metadata of files is WPR: Words Per Records. This
|
||||||
|
is a numeric value that sets the length of each logical record of
|
||||||
|
the file (in units of 16-bit words). It defaults to 128 (i.e.
|
||||||
|
logical and physical records are the same thing). It can be
|
||||||
|
set by the "wpr" option when putting files into the image.
|
||||||
|
* There is no fragmentation map in the filesystem: each file
|
||||||
|
always occupy a contiguous set of physical records. This fact
|
||||||
|
could prevent the putting of a file into an image when there
|
||||||
|
is no single block of free records big enough to hold the file
|
||||||
|
even though the total amount of free space would be sufficient.
|
||||||
|
|
||||||
|
**** dir command ****
|
||||||
|
The format of the "attr" part of file listing is as follows:
|
||||||
|
%c '*' if file has the protection bit set, else ' '
|
||||||
|
%02x Hexadecimal value of file type (00-1f)
|
||||||
|
%c '?' if file type is not valid, else ' '
|
||||||
|
%4u Number of logical records
|
||||||
|
%4u WPR * 2 (i.e. bytes per logical record)
|
||||||
|
%3u First physical record of file
|
||||||
|
|
||||||
|
**** get command ****
|
||||||
|
A file can be extracted from an image with or without an explicit
|
||||||
|
extension. If an extension is given, it must match the one corresponding
|
||||||
|
to file type.
|
||||||
|
|
||||||
|
**** getall command ****
|
||||||
|
Files are extracted with their "fake" extension.
|
||||||
|
|
||||||
|
**** put command ****
|
||||||
|
File type can be specified explicitly through the "ftype" option.
|
||||||
|
If this option is "auto" (the default), type is deduced from file
|
||||||
|
extension, if present. When extension is not given or it doesn't
|
||||||
|
match any known type, file type is set to "DATA".
|
||||||
|
WPR can be set through the "wpr" option. If it's 0 (the default),
|
||||||
|
WPR is set to 128.
|
||||||
|
|
||||||
|
**** del command ****
|
||||||
|
File extension is ignored, if present.
|
||||||
|
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
||||||
@ -26,7 +81,8 @@
|
|||||||
#define MAX_DIR_ENTRIES 42 // And the answer is.... the maximum number of entries in the directory!
|
#define MAX_DIR_ENTRIES 42 // And the answer is.... the maximum number of entries in the directory!
|
||||||
#define DIR_COPIES 2 // Count of directory copies
|
#define DIR_COPIES 2 // Count of directory copies
|
||||||
#define CHARS_PER_FNAME 6 // Maximum characters in a filename
|
#define CHARS_PER_FNAME 6 // Maximum characters in a filename
|
||||||
#define CHARS_PER_FNAME_EXT (CHARS_PER_FNAME + 1 + 4) // Characters in filename + extension
|
#define CHARS_PER_EXT 4 // Characters in file extension. Extension is encoded as file type, it's not actually stored in directory as characters.
|
||||||
|
#define CHARS_PER_FNAME_EXT (CHARS_PER_FNAME + 1 + CHARS_PER_EXT) // Characters in filename + extension
|
||||||
#define PAD_WORD 0xffff // Word value for padding
|
#define PAD_WORD 0xffff // Word value for padding
|
||||||
#define FIRST_FILE_SECTOR (FIRST_DIR_SECTOR + SECTORS_PER_DIR * DIR_COPIES) // First file sector
|
#define FIRST_FILE_SECTOR (FIRST_DIR_SECTOR + SECTORS_PER_DIR * DIR_COPIES) // First file sector
|
||||||
#define MAGIC 0x5441434f // Magic value at start of image file: "TACO"
|
#define MAGIC 0x5441434f // Magic value at start of image file: "TACO"
|
||||||
@ -112,13 +168,20 @@ public:
|
|||||||
void unset_sector(unsigned s_no);
|
void unset_sector(unsigned s_no);
|
||||||
bool get_sector(unsigned s_no , tape_word_t *s_data);
|
bool get_sector(unsigned s_no , tape_word_t *s_data);
|
||||||
|
|
||||||
bool get_dir_entry(unsigned idx , dir_entry_t& entry);
|
bool get_dir_entry(unsigned idx , const dir_entry_t*& entry) const;
|
||||||
bool get_dir_entry(const char* filename , dir_entry_t& entry);
|
bool find_file(const char *filename , bool ignore_ext , unsigned& idx) const;
|
||||||
|
|
||||||
|
void delete_dir_entry(unsigned idx);
|
||||||
|
|
||||||
|
bool find_free_block(unsigned blocks , unsigned& first_s) const;
|
||||||
|
|
||||||
|
bool alloc_new_file(unsigned blocks , dir_entry_t*& entry);
|
||||||
|
|
||||||
static void tape_word_to_bytes(tape_word_t w , UINT8& bh , UINT8& bl);
|
static void tape_word_to_bytes(tape_word_t w , UINT8& bh , UINT8& bl);
|
||||||
static void bytes_to_tape_word(UINT8 bh , UINT8 bl , tape_word_t& w);
|
static void bytes_to_tape_word(UINT8 bh , UINT8 bl , tape_word_t& w);
|
||||||
|
|
||||||
static void get_filename_and_ext(const dir_entry_t& ent , char *out , bool& qmark);
|
static void get_filename_and_ext(const dir_entry_t& ent , bool inc_ext , char *out , bool& qmark);
|
||||||
|
static void split_filename_and_ext(const char *filename , char *fname , char *ext);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool dirty;
|
bool dirty;
|
||||||
@ -463,7 +526,14 @@ imgtoolerr_t tape_image_t::save_to_file(imgtool_stream *stream)
|
|||||||
|
|
||||||
unsigned tape_image_t::free_sectors(void) const
|
unsigned tape_image_t::free_sectors(void) const
|
||||||
{
|
{
|
||||||
return TOT_SECTORS - alloc_map.count();
|
std::bitset<TOT_SECTORS> tmp(alloc_map);
|
||||||
|
|
||||||
|
// Reserve sectors that cannot be allocated to files
|
||||||
|
for (unsigned i = 0; i < FIRST_FILE_SECTOR; i++) {
|
||||||
|
tmp[ i ] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TOT_SECTORS - tmp.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tape_image_t::set_sector(unsigned s_no , const tape_word_t *s_data)
|
void tape_image_t::set_sector(unsigned s_no , const tape_word_t *s_data)
|
||||||
@ -493,32 +563,135 @@ bool tape_image_t::get_sector(unsigned s_no , tape_word_t *s_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tape_image_t::get_dir_entry(unsigned idx , dir_entry_t& entry)
|
bool tape_image_t::get_dir_entry(unsigned idx , const dir_entry_t*& entry) const
|
||||||
{
|
{
|
||||||
if (idx >= dir.size()) {
|
if (idx >= dir.size()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
entry = dir[ idx ];
|
entry = &dir[ idx ];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tape_image_t::get_dir_entry(const char* filename , dir_entry_t& entry)
|
bool tape_image_t::find_file(const char *filename , bool ignore_ext , unsigned& idx) const
|
||||||
{
|
{
|
||||||
for (const dir_entry_t& ent : dir) {
|
char fname[ CHARS_PER_FNAME_EXT + 1 ];
|
||||||
|
char ext[ CHARS_PER_EXT + 1 ];
|
||||||
|
|
||||||
|
split_filename_and_ext(filename, fname, ext);
|
||||||
|
|
||||||
|
bool has_ext = !ignore_ext && *ext != '\0';
|
||||||
|
|
||||||
|
if (has_ext) {
|
||||||
|
strcat(fname , ".");
|
||||||
|
strcat(fname , ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = dir.cbegin(); i < dir.cend(); i++) {
|
||||||
char full_fname[ CHARS_PER_FNAME_EXT + 1 ];
|
char full_fname[ CHARS_PER_FNAME_EXT + 1 ];
|
||||||
bool qmark;
|
bool qmark;
|
||||||
|
|
||||||
get_filename_and_ext(ent, full_fname, qmark);
|
get_filename_and_ext(*i, has_ext, full_fname, qmark);
|
||||||
|
|
||||||
if (strcmp(filename , full_fname) == 0) {
|
if (strcmp(fname , full_fname) == 0) {
|
||||||
entry = ent;
|
idx = i - dir.cbegin();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tape_image_t::delete_dir_entry(unsigned idx)
|
||||||
|
{
|
||||||
|
const dir_entry_t& ent = dir[ idx ];
|
||||||
|
|
||||||
|
// Release all sectors of file
|
||||||
|
for (unsigned i = ent.filepos; i < ent.filepos + ent.n_sects; i++) {
|
||||||
|
unset_sector(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.erase(dir.begin() + idx);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tape_image_t::find_free_block(unsigned blocks , unsigned& first_s) const
|
||||||
|
{
|
||||||
|
if (blocks >= (TOT_SECTORS - FIRST_FILE_SECTOR)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::bitset<TOT_SECTORS> scanner;
|
||||||
|
|
||||||
|
for (unsigned i = FIRST_FILE_SECTOR; i < (FIRST_FILE_SECTOR + blocks); i++) {
|
||||||
|
scanner[ i ] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = FIRST_FILE_SECTOR; i <= (TOT_SECTORS - blocks); i++) {
|
||||||
|
std::bitset<TOT_SECTORS> tmp_map(alloc_map & scanner);
|
||||||
|
if (tmp_map.none()) {
|
||||||
|
first_s = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
scanner <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tape_image_t::alloc_new_file(unsigned blocks , dir_entry_t*& entry)
|
||||||
|
{
|
||||||
|
if (dir.size() >= MAX_DIR_ENTRIES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_entry_t new_entry;
|
||||||
|
|
||||||
|
memset(&new_entry.filename[ 0 ] , 0 , sizeof(new_entry.filename));
|
||||||
|
new_entry.protection = 0;
|
||||||
|
new_entry.filetype = 0;
|
||||||
|
new_entry.n_recs = 0;
|
||||||
|
new_entry.wpr = 0;
|
||||||
|
|
||||||
|
unsigned first_s;
|
||||||
|
|
||||||
|
if (!find_free_block(blocks, first_s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_entry.filepos = (UINT16)first_s;
|
||||||
|
new_entry.n_sects = blocks;
|
||||||
|
|
||||||
|
dir.push_back(new_entry);
|
||||||
|
entry = &dir.back();
|
||||||
|
dirty = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tape_image_t::split_filename_and_ext(const char *filename , char *fname , char *ext)
|
||||||
|
{
|
||||||
|
char *fname_fence = fname + CHARS_PER_FNAME;
|
||||||
|
|
||||||
|
while (fname < fname_fence && *filename != '\0' && *filename != '.') {
|
||||||
|
*fname++ = *filename++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fname = '\0';
|
||||||
|
|
||||||
|
while (*filename != '\0' && *filename != '.') {
|
||||||
|
filename++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*filename == '\0') {
|
||||||
|
*ext = '\0';
|
||||||
|
} else {
|
||||||
|
filename++;
|
||||||
|
strncpy(ext , filename , CHARS_PER_EXT);
|
||||||
|
ext[ CHARS_PER_EXT ] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tape_image_t::wipe_sector(tape_word_t *s)
|
void tape_image_t::wipe_sector(tape_word_t *s)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < WORDS_PER_SECTOR; i++) {
|
for (unsigned i = 0; i < WORDS_PER_SECTOR; i++) {
|
||||||
@ -660,7 +833,7 @@ static const char *const filetype_attrs[] = {
|
|||||||
OPRM_ATTR_STR // 7
|
OPRM_ATTR_STR // 7
|
||||||
};
|
};
|
||||||
|
|
||||||
void tape_image_t::get_filename_and_ext(const dir_entry_t& ent , char *out , bool& qmark)
|
void tape_image_t::get_filename_and_ext(const dir_entry_t& ent , bool inc_ext , char *out , bool& qmark)
|
||||||
{
|
{
|
||||||
strncpy(&out[ 0 ] , (const char*)&ent.filename[ 0 ] , CHARS_PER_FNAME);
|
strncpy(&out[ 0 ] , (const char*)&ent.filename[ 0 ] , CHARS_PER_FNAME);
|
||||||
out[ CHARS_PER_FNAME ] = '\0';
|
out[ CHARS_PER_FNAME ] = '\0';
|
||||||
@ -675,8 +848,10 @@ void tape_image_t::get_filename_and_ext(const dir_entry_t& ent , char *out , boo
|
|||||||
qmark = (type_low == DATA_FILETYPE && type_hi == 3) ||
|
qmark = (type_low == DATA_FILETYPE && type_hi == 3) ||
|
||||||
(type_low != DATA_FILETYPE && type_hi != 2);
|
(type_low != DATA_FILETYPE && type_hi != 2);
|
||||||
|
|
||||||
|
if (inc_ext) {
|
||||||
strcat(out , ".");
|
strcat(out , ".");
|
||||||
strcat(out , filetype_str);
|
strcat(out , filetype_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tape_image_t::decode_dir(void)
|
bool tape_image_t::decode_dir(void)
|
||||||
@ -864,7 +1039,7 @@ static imgtoolerr_t hp9845_tape_next_enum (imgtool_directory *enumeration, imgto
|
|||||||
tape_image_t& tape_image = get_tape_image(state);
|
tape_image_t& tape_image = get_tape_image(state);
|
||||||
dir_state_t *ds = (dir_state_t*)imgtool_directory_extrabytes(enumeration);
|
dir_state_t *ds = (dir_state_t*)imgtool_directory_extrabytes(enumeration);
|
||||||
|
|
||||||
dir_entry_t entry;
|
const dir_entry_t *entry = nullptr;
|
||||||
|
|
||||||
if (!tape_image.get_dir_entry(ds->dir_idx, entry)) {
|
if (!tape_image.get_dir_entry(ds->dir_idx, entry)) {
|
||||||
ent->eof = 1;
|
ent->eof = 1;
|
||||||
@ -873,12 +1048,12 @@ static imgtoolerr_t hp9845_tape_next_enum (imgtool_directory *enumeration, imgto
|
|||||||
|
|
||||||
bool qmark;
|
bool qmark;
|
||||||
|
|
||||||
tape_image_t::get_filename_and_ext(entry, ent->filename, qmark);
|
tape_image_t::get_filename_and_ext(*entry, true, ent->filename, qmark);
|
||||||
|
|
||||||
// "filename" and "attr" fields try to look like the output of the "CAT" command
|
// "filename" and "attr" fields try to look like the output of the "CAT" command
|
||||||
snprintf(ent->attr , sizeof(ent->attr) , "%c %02x%c %4u %4u %3u" , entry.protection ? '*' : ' ' , entry.filetype , qmark ? '?' : ' ' , entry.n_recs , entry.wpr * 2 , entry.filepos);
|
snprintf(ent->attr , sizeof(ent->attr) , "%c %02x%c %4u %4u %3u" , entry->protection ? '*' : ' ' , entry->filetype , qmark ? '?' : ' ' , entry->n_recs , entry->wpr * 2 , entry->filepos);
|
||||||
|
|
||||||
ent->filesize = entry.n_sects * SECTOR_LEN;
|
ent->filesize = entry->n_sects * SECTOR_LEN;
|
||||||
}
|
}
|
||||||
return IMGTOOLERR_SUCCESS;
|
return IMGTOOLERR_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -898,17 +1073,22 @@ static imgtoolerr_t hp9845_tape_read_file(imgtool_partition *partition, const ch
|
|||||||
tape_state_t& state = get_tape_state(imgtool_partition_image(partition));
|
tape_state_t& state = get_tape_state(imgtool_partition_image(partition));
|
||||||
tape_image_t& tape_image = get_tape_image(state);
|
tape_image_t& tape_image = get_tape_image(state);
|
||||||
|
|
||||||
dir_entry_t ent;
|
unsigned idx;
|
||||||
|
|
||||||
if (!tape_image.get_dir_entry(filename, ent)) {
|
if (!tape_image.find_file(filename , false , idx)) {
|
||||||
return IMGTOOLERR_FILENOTFOUND;
|
return IMGTOOLERR_FILENOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned sect_no = ent.filepos;
|
const dir_entry_t *ent = nullptr;
|
||||||
|
|
||||||
|
tape_image.get_dir_entry(idx, ent);
|
||||||
|
|
||||||
|
unsigned sect_no = ent->filepos;
|
||||||
|
unsigned n_sects = ent->n_sects;
|
||||||
tape_word_t buff_w[ WORDS_PER_SECTOR ];
|
tape_word_t buff_w[ WORDS_PER_SECTOR ];
|
||||||
UINT8 buff_b[ SECTOR_LEN ];
|
UINT8 buff_b[ SECTOR_LEN ];
|
||||||
|
|
||||||
while (ent.n_sects--) {
|
while (n_sects--) {
|
||||||
if (!tape_image.get_sector(sect_no++, &buff_w[ 0 ])) {
|
if (!tape_image.get_sector(sect_no++, &buff_w[ 0 ])) {
|
||||||
return IMGTOOLERR_READERROR;
|
return IMGTOOLERR_READERROR;
|
||||||
}
|
}
|
||||||
@ -922,6 +1102,125 @@ static imgtoolerr_t hp9845_tape_read_file(imgtool_partition *partition, const ch
|
|||||||
return IMGTOOLERR_SUCCESS;
|
return IMGTOOLERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static imgtoolerr_t hp9845_tape_write_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, util::option_resolution *opts)
|
||||||
|
{
|
||||||
|
tape_state_t& state = get_tape_state(imgtool_partition_image(partition));
|
||||||
|
tape_image_t& tape_image = get_tape_image(state);
|
||||||
|
|
||||||
|
unsigned idx;
|
||||||
|
|
||||||
|
if (tape_image.find_file(filename , true , idx)) {
|
||||||
|
// When overwriting a file, delete its old version first
|
||||||
|
tape_image.delete_dir_entry(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned blocks = (unsigned)((stream_size(sourcef) + SECTOR_LEN - 1) / SECTOR_LEN);
|
||||||
|
|
||||||
|
if (!blocks) {
|
||||||
|
fprintf(stderr , "Null file, not writing..\n");
|
||||||
|
return IMGTOOLERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_entry_t *ent = nullptr;
|
||||||
|
|
||||||
|
if (!tape_image.alloc_new_file(blocks, ent)) {
|
||||||
|
return IMGTOOLERR_NOSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned s_no = ent->filepos;
|
||||||
|
|
||||||
|
char fname[ CHARS_PER_FNAME + 1 ];
|
||||||
|
char ext[ CHARS_PER_EXT + 1 ];
|
||||||
|
|
||||||
|
tape_image_t::split_filename_and_ext(filename, fname, ext);
|
||||||
|
|
||||||
|
strncpy((char*)&ent->filename[ 0 ] , fname , CHARS_PER_FNAME);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < blocks; i++) {
|
||||||
|
tape_word_t buff_w[ WORDS_PER_SECTOR ];
|
||||||
|
UINT8 buff_b[ SECTOR_LEN ];
|
||||||
|
|
||||||
|
memset(&buff_b[ 0 ] , 0 , sizeof(buff_b));
|
||||||
|
|
||||||
|
if (stream_read(sourcef , buff_b , SECTOR_LEN) != SECTOR_LEN && i != (blocks - 1)) {
|
||||||
|
return IMGTOOLERR_READERROR;
|
||||||
|
}
|
||||||
|
for (unsigned j = 0; j < WORDS_PER_SECTOR; j++) {
|
||||||
|
tape_image_t::bytes_to_tape_word(buff_b[ 2 * j ], buff_b[ 2 * j + 1 ], buff_w[ j ]);
|
||||||
|
}
|
||||||
|
tape_image.set_sector(s_no, buff_w);
|
||||||
|
s_no++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wpr = opts->lookup_int('W');
|
||||||
|
if (wpr == 0) {
|
||||||
|
wpr = WORDS_PER_SECTOR;
|
||||||
|
} else if (wpr > (blocks * WORDS_PER_SECTOR)) {
|
||||||
|
fprintf(stderr , "WPR value too large, using %u\n" , WORDS_PER_SECTOR);
|
||||||
|
wpr = WORDS_PER_SECTOR;
|
||||||
|
}
|
||||||
|
ent->wpr = (UINT16)wpr;
|
||||||
|
|
||||||
|
ent->n_recs = (UINT16)((blocks * WORDS_PER_SECTOR) / wpr);
|
||||||
|
|
||||||
|
unsigned type_low;
|
||||||
|
|
||||||
|
if (opts->lookup_int('T') == 0) {
|
||||||
|
// File type defaults to DATA if no extension is given or extension is invalid
|
||||||
|
type_low = DATA_FILETYPE;
|
||||||
|
for (unsigned i = 0; i < 8; i++) {
|
||||||
|
if (strcmp(filetype_attrs[ i ] , ext) == 0) {
|
||||||
|
type_low = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type_low = opts->lookup_int('T') - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See tape_image_t::get_filename_and_ext for the logic behind file type
|
||||||
|
if (type_low == DATA_FILETYPE) {
|
||||||
|
ent->filetype = (UINT8)type_low + (1U << 3);
|
||||||
|
} else {
|
||||||
|
ent->filetype = (UINT8)type_low + (2U << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IMGTOOLERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static imgtoolerr_t hp9845_tape_delete_file(imgtool_partition *partition, const char *filename)
|
||||||
|
{
|
||||||
|
tape_state_t& state = get_tape_state(imgtool_partition_image(partition));
|
||||||
|
tape_image_t& tape_image = get_tape_image(state);
|
||||||
|
|
||||||
|
unsigned idx;
|
||||||
|
|
||||||
|
if (!tape_image.find_file(filename , true , idx)) {
|
||||||
|
return IMGTOOLERR_FILENOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
tape_image.delete_dir_entry(idx);
|
||||||
|
|
||||||
|
return IMGTOOLERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HP9845_WRITEFILE_OPTSPEC "W[0]-65535;T[0]-8"
|
||||||
|
|
||||||
|
OPTION_GUIDE_START(hp9845_write_optguide)
|
||||||
|
OPTION_INT('W' , "wpr" , "Words per record")
|
||||||
|
OPTION_ENUM_START('T' , "ftype" , "File type")
|
||||||
|
OPTION_ENUM(0 , "auto" , "Automatic (\"DATA\" or by extension)")
|
||||||
|
OPTION_ENUM(1 , "U" , "BKUP")
|
||||||
|
OPTION_ENUM(2 , "D" , "DATA")
|
||||||
|
OPTION_ENUM(3 , "P" , "PROG")
|
||||||
|
OPTION_ENUM(4 , "K" , "KEYS")
|
||||||
|
OPTION_ENUM(5 , "T" , "BDAT")
|
||||||
|
OPTION_ENUM(6 , "A" , "ALL")
|
||||||
|
OPTION_ENUM(7 , "B" , "BPRG")
|
||||||
|
OPTION_ENUM(8 , "O" , "OPRM")
|
||||||
|
OPTION_ENUM_END
|
||||||
|
OPTION_GUIDE_END
|
||||||
|
|
||||||
void hp9845_tape_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
|
void hp9845_tape_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -976,5 +1275,21 @@ void hp9845_tape_get_info(const imgtool_class *imgclass, UINT32 state, union img
|
|||||||
case IMGTOOLINFO_PTR_READ_FILE:
|
case IMGTOOLINFO_PTR_READ_FILE:
|
||||||
info->read_file = hp9845_tape_read_file;
|
info->read_file = hp9845_tape_read_file;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IMGTOOLINFO_PTR_WRITE_FILE:
|
||||||
|
info->write_file = hp9845_tape_write_file;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMGTOOLINFO_PTR_DELETE_FILE:
|
||||||
|
info->delete_file = hp9845_tape_delete_file;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE:
|
||||||
|
info->writefile_optguide = &hp9845_write_optguide;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMGTOOLINFO_STR_WRITEFILE_OPTSPEC:
|
||||||
|
strcpy(info->s = imgtool_temp_str(), HP9845_WRITEFILE_OPTSPEC);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user