summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/floptool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/floptool.cpp')
-rw-r--r--src/tools/floptool.cpp815
1 files changed, 619 insertions, 196 deletions
diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp
index 1953e7b0538..9ac9c3231ae 100644
--- a/src/tools/floptool.cpp
+++ b/src/tools/floptool.cpp
@@ -1,305 +1,728 @@
// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
+// copyright-holders:Olivier Galibert
/***************************************************************************
- main.c
-
- Floptool command line front end
-
- 20/07/2011 Initial version by Miodrag Milanovic
+ (Floppy) image command-line manager
***************************************************************************/
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <time.h>
-#include <stdarg.h>
-#include <assert.h>
+#include "image_handler.h"
+
+#include "formats/fsblk.h"
#include "corestr.h"
+#include "ioprocs.h"
+#include "path.h"
+#include "strformat.h"
-#include "formats/mfi_dsk.h"
-#include "formats/dfi_dsk.h"
-#include "formats/ipf_dsk.h"
+#include "osdcomm.h"
-#include "formats/hxcmfm_dsk.h"
-#include "formats/ami_dsk.h"
+#include <cassert>
+#include <cctype>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <exception>
-#include "formats/st_dsk.h"
-#include "formats/pasti_dsk.h"
-#include "formats/dsk_dsk.h"
+static formats_table formats;
-#include "formats/d88_dsk.h"
-#include "formats/imd_dsk.h"
-#include "formats/td0_dsk.h"
-#include "formats/cqm_dsk.h"
-#include "formats/pc_dsk.h"
-#include "formats/naslite_dsk.h"
+static void display_usage(const char *first_argument)
+{
+ std::string exe_name(core_filename_extract_base(first_argument));
-#include "formats/ap_dsk35.h"
-#include "formats/ap2_dsk.h"
+ fprintf(stderr, "Usage: \n");
+ fprintf(stderr, " %s identify <inputfile> [<inputfile> ...] -- Identify an image format\n", exe_name.c_str());
+ fprintf(stderr, " %s flopconvert [input_format|auto] output_format <inputfile> <outputfile> -- Convert a floppy image\n", exe_name.c_str());
+ fprintf(stderr, " %s flopcreate output_format filesystem <outputfile> -- Create a preformatted floppy image\n", exe_name.c_str());
+ fprintf(stderr, " %s flopdir input_format filesystem <image> -- List the contents of a floppy image\n", exe_name.c_str());
+ fprintf(stderr, " %s flopread input_format filesystem <image> <path> <outputfile> -- Extract a file from a floppy image\n", exe_name.c_str());
+ fprintf(stderr, " %s flopwrite input_format filesystem <image> <inputfile> <path> -- Write a file into a floppy image\n", exe_name.c_str());
+ fprintf(stderr, " %s hddir filesystem <image> -- List the contents of a hard disk image\n", exe_name.c_str());
+ fprintf(stderr, " %s hdread filesystem <image> <path> <outputfile> -- Extract a file from a hard disk image\n", exe_name.c_str());
+ fprintf(stderr, " %s hdwrite filesystem <image> <inputfile> <path> -- Write a file into a hard disk image\n", exe_name.c_str());
+ fprintf(stderr, " %s version -- Display the current version of floptool\n", exe_name.c_str());
+}
-#include "formats/atom_dsk.h"
-#include "formats/acorn_dsk.h"
+static void display_formats()
+{
+ int sk = 0;
+ for(const auto &e : formats.floppy_format_info_by_key) {
+ int sz = e.first.size();
+ if(sz > sk)
+ sk = sz;
+ }
-#include "formats/oric_dsk.h"
+ for(const auto &e : formats.filesystem_format_by_key) {
+ int sz = e.first.size();
+ if(sz > sk)
+ sk = sz;
+ }
-#include "formats/applix_dsk.h"
+ for(const auto &e : formats.floppy_create_info_by_key) {
+ int sz = e.first.size();
+ if(sz > sk)
+ sk = sz;
+ }
-#include "formats/hpi_dsk.h"
+ fprintf(stderr, "Supported floppy formats:\n\n");
+ for(const auto &e : formats.floppy_format_info_by_category)
+ if(!e.second.empty()) {
+ fprintf(stderr, "%s:\n", e.first.c_str());
+ for(auto *fif : e.second)
+ fprintf(stderr, " %-*s r%c - %s [%s]\n", sk, fif->m_format->name(), fif->m_format->supports_save() ? 'w' : '-', fif->m_format->description(), fif->m_format->extensions());
+ }
-#include "formats/dvk_mx_dsk.h"
-#include "formats/aim_dsk.h"
-#include "formats/m20_dsk.h"
+ fprintf(stderr, "\n\n");
+ fprintf(stderr, "Supported filesystems (with floppy formatting names):\n\n");
+ for(const auto &e : formats.filesystem_format_by_category)
+ if(!e.second.empty()) {
+ fprintf(stderr, "%s:\n", e.first.c_str());
+ for(const auto &f : e.second) {
+ fprintf(stderr, " %-*s %c%c%c %c%c%c - %s\n",
+ sk,
+ f->m_manager->name(),
+ f->m_floppy || f->m_floppy_raw ? 'F' : '-',
+ f->m_hd ? 'H' : '-',
+ f->m_cd ? 'C' : '-',
+ f->m_manager->can_format() || f->m_floppy_raw ? 'f' : '-',
+ f->m_manager->can_read() ? 'r' : '-',
+ f->m_manager->can_write() ? 'w' : '-',
+ f->m_manager->description());
+ for(auto &f2 : f->m_floppy_create)
+ fprintf(stderr, " %-*s - %s\n",
+ sk,
+ f2->m_name,
+ f2->m_description);
+ }
+ }
+}
-#include "formats/flex_dsk.h"
-#include "formats/uniflex_dsk.h"
+static void display_full_usage(char *argv[])
+{
+ /* Usage */
+ fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MAME\n\n");
+ display_usage(argv[0]);
+ fprintf(stderr, "\n");
+ display_formats();
+}
+static int identify(int argc, char *argv[])
+{
+ // Need to detect CHDs too
-static floppy_format_type floppy_formats[] = {
- FLOPPY_MFI_FORMAT,
- FLOPPY_DFI_FORMAT,
- FLOPPY_IPF_FORMAT,
+ if(argc<3) {
+ fprintf(stderr, "Missing name of file to identify.\n\n");
+ display_usage(argv[0]);
+ return 1;
+ }
- FLOPPY_MFM_FORMAT,
- FLOPPY_ADF_FORMAT,
+ int sz = 0;
+ for(int i=2; i<argc; i++) {
+ int len = strlen(argv[i]);
+ if(len > sz)
+ sz = len;
+ }
- FLOPPY_ST_FORMAT,
- FLOPPY_MSA_FORMAT,
- FLOPPY_PASTI_FORMAT,
+ for(int i=2; i<argc; i++) {
+ image_handler ih;
+ ih.set_on_disk_path(argv[i]);
+ auto scores = ih.identify(formats);
+ if(scores.empty())
+ printf("%-*s : Unknown format\n", sz, argv[i]);
+ int sz2 = 0;
+ for(const auto &e : scores) {
+ int len = strlen(e.second->m_format->name());
+ if(len > sz2)
+ sz2 = len;
+ }
- FLOPPY_DSK_FORMAT,
+ bool first = true;
+ for(const auto &e : scores) {
+ printf("%-*s %c %c%c%c%c%c - %-*s %s\n", sz, first ? argv[i] : "", first ? ':' : ' ',
+ e.first & 0x10 ? '+' : '.',
+ e.first & 0x08 ? '+' : '.',
+ e.first & 0x04 ? '+' : '.',
+ e.first & 0x02 ? '+' : '.',
+ e.first & 0x01 ? '+' : '.',
+ sz2, e.second->m_format->name(), e.second->m_format->description());
+ first = false;
+ }
+ }
+ return 0;
+}
+
+static const floppy_format_info *find_floppy_source_format(const char *name, image_handler &ih)
+{
+ const floppy_format_info *source_format;
+ if(!core_stricmp(name, "auto")) {
+ auto scores = ih.identify(formats);
+ if(scores.empty()) {
+ fprintf(stderr, "Error: Could not identify the format of file %s\n", ih.get_on_disk_path().c_str());
+ return nullptr;
+ }
+ if(scores.size() >= 2 && scores[0].first == scores[1].first) {
+ fprintf(stderr, "Ambiguous source format. Possible formats:\n");
+ int sz = 0;
+ for(const auto &e : scores) {
+ int len = strlen(e.second->m_format->name());
+ if(len > sz)
+ sz = len;
+ }
+
+ for(const auto &e : scores)
+ printf(" %3d - %-*s %s\n", e.first, sz, e.second->m_format->name(), e.second->m_format->description());
+ return nullptr;
+ }
+ source_format = scores[0].second;
- FLOPPY_D88_FORMAT,
- FLOPPY_IMD_FORMAT,
- FLOPPY_TD0_FORMAT,
- FLOPPY_CQM_FORMAT,
- FLOPPY_PC_FORMAT,
- FLOPPY_NASLITE_FORMAT,
+ } else {
+ source_format = formats.find_floppy_format_info_by_key(name);
+ if(!source_format) {
+ fprintf(stderr, "Error: Format '%s' unknown\n", name);
+ return nullptr;
- FLOPPY_DC42_FORMAT,
- FLOPPY_A216S_FORMAT,
- FLOPPY_RWTS18_FORMAT,
- FLOPPY_EDD_FORMAT,
- FLOPPY_WOZ_FORMAT,
+ }
+ }
+ return source_format;
+}
- FLOPPY_ATOM_FORMAT,
- FLOPPY_ACORN_SSD_FORMAT,
- FLOPPY_ACORN_DSD_FORMAT,
- FLOPPY_ACORN_DOS_FORMAT,
- FLOPPY_ACORN_ADFS_OLD_FORMAT,
- FLOPPY_ACORN_ADFS_NEW_FORMAT,
+static int flopconvert(int argc, char *argv[])
+{
+ if(argc!=6) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
+ return 1;
+ }
- FLOPPY_ORIC_DSK_FORMAT,
+ image_handler ih;
+ ih.set_on_disk_path(argv[4]);
- FLOPPY_APPLIX_FORMAT,
+ const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih);
+ if(!source_format)
+ return 1;
- FLOPPY_HPI_FORMAT,
+ const floppy_format_info *dest_format = formats.find_floppy_format_info_by_key(argv[3]);
+ if(!dest_format) {
+ fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]);
+ return 1;
+ }
+ if(!dest_format->m_format->supports_save()) {
+ fprintf(stderr, "Error: Saving to format '%s' unsupported\n", argv[3]);
+ return 1;
+ }
- FLOPPY_DVK_MX_FORMAT,
- FLOPPY_AIM_FORMAT,
- FLOPPY_M20_FORMAT,
+ if(ih.floppy_load(*source_format)) {
+ fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name());
+ return 1;
+ }
- FLOPPY_FLEX_FORMAT,
- FLOPPY_UNIFLEX_FORMAT
-};
+ ih.set_on_disk_path(argv[5]);
-void CLIB_DECL ATTR_PRINTF(1,2) logerror(const char *format, ...)
-{
- va_list arg;
- va_start(arg, format);
- vprintf(format, arg);
- va_end(arg);
+ if(ih.floppy_save(*dest_format)) {
+ fprintf(stderr, "Error: Saving as format '%s' failed\n", dest_format->m_format->name());
+ return 1;
+ }
+
+ return 0;
}
-enum { FORMAT_COUNT = ARRAY_LENGTH(floppy_formats) };
+static fs::meta_data extract_meta_data(int &argc, char *argv[])
+{
+ fs::meta_data result;
-static floppy_image_format_t *formats[FORMAT_COUNT];
+ int new_argc = 0;
+ for (int i = 0; i < argc; i++)
+ {
+ std::optional<fs::meta_name> attrname;
+ if (argv[i][0] == '-' && i < argc - 1)
+ attrname = fs::meta_data::from_entry_name(&argv[i][1]);
+
+ if (attrname)
+ {
+ // we found a metadata variable; set it
+ result.set(*attrname, argv[i + 1]);
+ i++;
+ }
+ else
+ {
+ // we didn't; update argv
+ argv[new_argc++] = argv[i];
+ }
+ }
+
+ // we're done; update the argument count
+ argc = new_argc;
+ return result;
+}
-static void init_formats()
+static int flopcreate(int argc, char *argv[])
{
- for(int i=0; i != FORMAT_COUNT; i++)
- formats[i] = floppy_formats[i]();
+ fs::meta_data meta = extract_meta_data(argc, argv);
+
+ if(argc!=5) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
+ return 1;
+ }
+
+ auto dest_format = formats.find_floppy_format_info_by_key(argv[2]);
+ if(!dest_format) {
+ fprintf(stderr, "Error: Floppy format '%s' unknown\n", argv[2]);
+ return 1;
+ }
+ if(!dest_format->m_format->supports_save()) {
+ fprintf(stderr, "Error: Saving to format '%s' unsupported\n", argv[2]);
+ return 1;
+ }
+
+ auto create_fs = formats.find_floppy_create_info_by_key(argv[3]);
+ if(!create_fs) {
+ fprintf(stderr, "Error: Floppy creation format '%s' unknown\n", argv[3]);
+ return 1;
+ }
+ if(create_fs->m_manager && !create_fs->m_manager->can_format()) {
+ fprintf(stderr, "Error: Floppy creation format '%s' does not support creating new images\n", argv[3]);
+ return 1;
+ }
+
+ image_handler ih;
+ ih.set_on_disk_path(argv[4]);
+
+ ih.floppy_create(*create_fs, meta);
+ return ih.floppy_save(*dest_format);
}
-static floppy_image_format_t *find_format_by_name(const char *name)
+static void dir_scan(fs::filesystem_t *fs, u32 depth, const std::vector<std::string> &path, std::vector<std::vector<std::string>> &entries, const std::unordered_map<fs::meta_name, size_t> &nmap, size_t nc, const std::vector<fs::meta_description> &dmetad, const std::vector<fs::meta_description> &fmetad)
{
- for(int i=0; i != FORMAT_COUNT; i++)
- if(!core_stricmp(name, formats[i]->name()))
- return formats[i];
- return nullptr;
+ std::string head;
+ for(u32 i = 0; i != depth; i++)
+ head += " ";
+ auto [err, contents] = fs->directory_contents(path);
+ if(err)
+ return; // FIXME: don't swallow errors
+ for(const auto &c : contents) {
+ size_t id = entries.size();
+ entries.resize(id+1);
+ entries[id].resize(nc);
+ switch(c.m_type) {
+ case fs::dir_entry_type::dir: {
+ for(const auto &m : dmetad) {
+ if(!c.m_meta.has(m.m_name))
+ continue;
+ size_t slot = nmap.find(m.m_name)->second;
+ std::string val = c.m_meta.get(m.m_name).as_string();
+ if(slot == 0)
+ val = head + "dir " + val;
+ entries[id][slot] = val;
+ }
+ auto npath = path;
+ npath.push_back(c.m_name);
+ dir_scan(fs, depth+1, npath, entries, nmap, nc, dmetad, fmetad);
+ break;
+ }
+ case fs::dir_entry_type::file: {
+ for(const auto &m : fmetad) {
+ if(!c.m_meta.has(m.m_name))
+ continue;
+ size_t slot = nmap.find(m.m_name)->second;
+ std::string val = c.m_meta.get(m.m_name).as_string();
+ if(slot == 0)
+ val = head + "file " + val;
+ entries[id][slot] = val;
+ }
+ break;
+ }
+ }
+ }
}
-static floppy_image_format_t *find_format_by_identify(io_generic *image)
+static int generic_dir(image_handler &ih)
{
- int best = 0;
- floppy_image_format_t *best_fif = nullptr;
-
- for(int i = 0; i != FORMAT_COUNT; i++) {
- floppy_image_format_t *fif = formats[i];
- int score = fif->identify(image, floppy_image::FF_UNKNOWN);
- if(score > best) {
- best = score;
- best_fif = fif;
+ auto [fsm, fs] = ih.get_fs();
+ auto vmetad = fsm->volume_meta_description();
+ auto fmetad = fsm->file_meta_description();
+ auto dmetad = fsm->directory_meta_description();
+
+ auto vmeta = fs->volume_metadata();
+ if(!vmeta.empty()) {
+ std::string vinf = "Volume:";
+ for(const auto &e : vmetad)
+ vinf += util::string_format(" %s=%s", fs::meta_data::entry_name(e.m_name), vmeta.get(e.m_name).as_string());
+ printf("%s\n\n", vinf.c_str());
+ }
+
+ std::vector<fs::meta_name> names;
+ names.push_back(fs::meta_name::name);
+ for(const auto &e : fmetad)
+ if(e.m_name != fs::meta_name::name)
+ names.push_back(e.m_name);
+ for(const auto &e : dmetad)
+ if(std::find(names.begin(), names.end(), e.m_name) == names.end())
+ names.push_back(e.m_name);
+
+ std::unordered_map<fs::meta_name, size_t> nmap;
+ for(size_t i = 0; i != names.size(); i++)
+ nmap[names[i]] = i;
+
+ std::vector<std::vector<std::string>> entries;
+
+ entries.resize(1);
+ for(fs::meta_name n : names)
+ entries[0].push_back(fs::meta_data::entry_name(n));
+
+ dir_scan(fs, 0, std::vector<std::string>(), entries, nmap, names.size(), dmetad, fmetad);
+
+ std::vector<u32> sizes(names.size());
+
+ for(const auto &e : entries)
+ for(unsigned int i=0; i != names.size(); i++)
+ sizes[i] = std::max<u32>(sizes[i], e[i].size());
+
+ for(const auto &e : entries) {
+ std::string l;
+ for(unsigned int i=0; i != names.size(); i++) {
+ if(i)
+ l += ' ';
+ l += util::string_format("%-*s", sizes[i], e[i]);
}
+ printf("%s\n", l.c_str());
}
- return best_fif;
+
+ return 0;
}
-static void display_usage()
+static int flopdir(int argc, char *argv[])
{
- fprintf(stderr, "Usage: \n");
- fprintf(stderr, " floptool.exe identify <inputfile> [<inputfile> ...]\n");
- fprintf(stderr, " floptool.exe convert [input_format|auto] output_format <inputfile> <outputfile>\n");
+ if(argc!=5) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
+ return 1;
+ }
+
+ image_handler ih;
+ ih.set_on_disk_path(argv[4]);
+
+ const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih);
+ if(!source_format)
+ return 1;
+
+ auto fs = formats.find_filesystem_format_by_key(argv[3]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]);
+ return 1;
+ }
+
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]);
+ return 1;
+ }
+
+ if(ih.floppy_load(*source_format)) {
+ fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name());
+ return 1;
+ }
+
+ if(ih.floppy_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
+ return 1;
+ }
+
+ return generic_dir(ih);
}
-static void display_formats()
+static int hddir(int argc, char *argv[])
{
- fprintf(stderr, "Supported formats:\n\n");
- for(int i = 0; i != FORMAT_COUNT; i++)
- {
- floppy_image_format_t *fif = formats[i];
- fprintf(stderr, "%15s - %s [%s]\n", fif->name(), fif->description(), fif->extensions());
+ if(argc!=4) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
+ return 1;
}
+
+ image_handler ih;
+ ih.set_on_disk_path(argv[3]);
+
+ auto fs = formats.find_filesystem_format_by_key(argv[2]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]);
+ return 1;
+ }
+
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]);
+ return 1;
+ }
+
+ if(ih.hd_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
+ return 1;
+ }
+
+ return generic_dir(ih);
}
-static void display_full_usage()
+
+static int generic_read(image_handler &ih, const char *srcpath, const char *dstpath)
{
- /* Usage */
- fprintf(stderr, "floptool - Generic floppy image manipulation tool for use with MAME\n\n");
- display_usage();
- fprintf(stderr, "\n");
- display_formats();
- fprintf(stderr, "\nExample usage:\n");
- fprintf(stderr, " floptool.exe identify image.dsk\n\n");
+ auto [fsm, fs] = ih.get_fs();
+ std::ignore = fsm;
+
+ std::vector<std::string> path = ih.path_split(srcpath);
+ auto [err, dfork] = fs->file_read(path);
+ if(err) {
+ fprintf(stderr, "File reading failed: %s\n", err.message().c_str());
+ return 1;
+ }
+ image_handler::fsave(dstpath, dfork);
+
+ auto [err2, rfork] = fs->file_rsrc_read(path);
+ if(!err2 && !rfork.empty())
+ image_handler::fsave_rsrc(image_handler::path_make_rsrc(dstpath), rfork);
+
+ return 0;
}
-static int identify(int argc, char *argv[])
+
+static int flopread(int argc, char *argv[])
{
- if (argc<3) {
- fprintf(stderr, "Missing name of file to identify.\n\n");
- display_usage();
+ if(argc!=7) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
return 1;
}
- for(int i=2; i<argc; i++) {
- char msg[4096];
- sprintf(msg, "Error opening %s for reading", argv[i]);
- FILE *f = fopen(argv[i], "rb");
- if (!f) {
- perror(msg);
- return 1;
- }
- io_generic io;
- io.file = f;
- io.procs = &stdio_ioprocs_noclose;
- io.filler = 0xff;
-
- floppy_image_format_t *best_fif = find_format_by_identify(&io);
- if (best_fif)
- printf("%s : %s\n", argv[i], best_fif->description());
- else
- printf("%s : Unknown format\n", argv[i]);
- fclose(f);
+ image_handler ih;
+ ih.set_on_disk_path(argv[4]);
+
+ const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih);
+ if(!source_format)
+ return 1;
+
+ auto fs = formats.find_filesystem_format_by_key(argv[3]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]);
+ return 1;
}
- return 0;
+
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]);
+ return 1;
+ }
+
+ if(ih.floppy_load(*source_format)) {
+ fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name());
+ return 1;
+ }
+
+ if(ih.floppy_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
+ return 1;
+ }
+
+ return generic_read(ih, argv[5], argv[6]);
}
-static int convert(int argc, char *argv[])
+static int hdread(int argc, char *argv[])
{
- if (argc!=6) {
+ if(argc!=6) {
fprintf(stderr, "Incorrect number of arguments.\n\n");
- display_usage();
+ display_usage(argv[0]);
return 1;
}
- floppy_image_format_t *source_format, *dest_format;
+ image_handler ih;
+ ih.set_on_disk_path(argv[3]);
- char msg[4096];
- sprintf(msg, "Error opening %s for reading", argv[4]);
- FILE *f = fopen(argv[4], "rb");
- if (!f) {
- perror(msg);
+ auto fs = formats.find_filesystem_format_by_key(argv[2]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]);
return 1;
}
- io_generic source_io;
- source_io.file = f;
- source_io.procs = &stdio_ioprocs_noclose;
- source_io.filler = 0xff;
- if(!core_stricmp(argv[2], "auto")) {
- source_format = find_format_by_identify(&source_io);
- if(!source_format) {
- fprintf(stderr, "Error: Could not identify the format of file %s\n", argv[4]);
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]);
+ return 1;
+ }
+
+ if(ih.hd_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
+ return 1;
+ }
+
+ return generic_read(ih, argv[4], argv[5]);
+}
+
+
+
+static int generic_write(image_handler &ih, const char *srcpath, const char *dstpath)
+{
+ auto [fsm, fs] = ih.get_fs();
+
+ std::vector<std::string> path = ih.path_split(dstpath);
+ auto [err, meta] = fs->metadata(path);
+ std::ignore = meta;
+
+ if(err == fs::error::not_found) {
+ fs::meta_data meta;
+ meta.set(fs::meta_name::name, path.back());
+ auto dpath = path;
+ dpath.pop_back();
+ err = fs->file_create(dpath, meta);
+ if(err) {
+ fprintf(stderr, "File creation failed: %s\n", err.message().c_str());
return 1;
}
+ }
- } else {
- source_format = find_format_by_name(argv[2]);
- if(!source_format) {
- fprintf(stderr, "Error: Format '%s' unknown\n", argv[2]);
- return 1;
+ auto dfork = image_handler::fload(srcpath);
+ err = fs->file_write(path, dfork);
+ if(err) {
+ fprintf(stderr, "File writing failed: %s\n", err.message().c_str());
+ return 1;
+ }
+
+ if(fsm->has_rsrc()) {
+ std::string rpath = image_handler::path_make_rsrc(dstpath);
+
+ if(image_handler::fexists(rpath)) {
+ auto rfork = image_handler::fload_rsrc(rpath);
+ if(!rfork.empty()) {
+ err = fs->file_rsrc_write(path, rfork);
+ fprintf(stderr, "File resource fork writing failed: %s\n", err.message().c_str());
+ return 1;
+ }
}
}
- dest_format = find_format_by_name(argv[3]);
- if(!dest_format) {
- fprintf(stderr, "Error: Format '%s' unknown\n", argv[3]);
+ return 0;
+}
+
+
+static int flopwrite(int argc, char *argv[])
+{
+ if(argc!=7) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
+ return 1;
+ }
+
+ image_handler ih;
+ ih.set_on_disk_path(argv[4]);
+
+ const floppy_format_info *source_format = find_floppy_source_format(argv[2], ih);
+ if(!source_format)
+ return 1;
+
+ auto fs = formats.find_filesystem_format_by_key(argv[3]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[3]);
+ return 1;
+ }
+
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[3]);
return 1;
}
- if(!dest_format->supports_save()) {
- fprintf(stderr, "Error: saving to format '%s' unsupported\n", argv[3]);
+
+ if(ih.floppy_load(*source_format)) {
+ fprintf(stderr, "Error: Loading as format '%s' failed\n", source_format->m_format->name());
+ return 1;
+ }
+
+ if(ih.floppy_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
+ return 1;
+ }
+
+ int err = generic_write(ih, argv[5], argv[6]);
+ if(err)
+ return err;
+
+ ih.fs_to_floppy();
+ if(ih.floppy_save(*source_format))
+ return 1;
+
+ return 0;
+}
+
+static int hdwrite(int argc, char *argv[])
+{
+ if(argc!=6) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage(argv[0]);
return 1;
}
- sprintf(msg, "Error opening %s for writing", argv[5]);
- f = fopen(argv[5], "wb");
- if (!f) {
- perror(msg);
+
+ image_handler ih;
+ ih.set_on_disk_path(argv[3]);
+
+ auto fs = formats.find_filesystem_format_by_key(argv[2]);
+ if(!fs) {
+ fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]);
return 1;
}
- io_generic dest_io;
- dest_io.file = f;
- dest_io.procs = &stdio_ioprocs_noclose;
- dest_io.filler = 0xff;
- floppy_image image(84, 2, floppy_image::FF_UNKNOWN);
- if(!source_format->load(&source_io, floppy_image::FF_UNKNOWN, &image)) {
- fprintf(stderr, "Error: parsing input file as '%s' failed\n", source_format->name());
+ if(!fs->m_manager || !fs->m_manager->can_read()) {
+ fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]);
return 1;
}
- if(!dest_format->save(&dest_io, &image)) {
- fprintf(stderr, "Error: writing output file as '%s' failed\n", dest_format->name());
+ if(ih.hd_mount_fs(*fs)) {
+ fprintf(stderr, "Error: Parsing as filesystem '%s' failed\n", fs->m_manager->name());
return 1;
}
- fclose((FILE *)source_io.file);
- fclose((FILE *)dest_io.file);
+ return generic_write(ih, argv[4], argv[5]);
+}
+static int version(int argc, char *argv[])
+{
+ extern const char build_version[];
+ fprintf(stdout, "%s\n", build_version);
return 0;
}
int CLIB_DECL main(int argc, char *argv[])
{
- init_formats();
+ formats.init();
- if (argc == 1) {
- display_full_usage();
+ if(argc == 1) {
+ display_full_usage(argv);
return 0;
}
- if (!core_stricmp("identify", argv[1]))
- return identify(argc, argv);
- else if (!core_stricmp("convert", argv[1]))
- return convert(argc, argv);
- else {
- fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
- display_usage();
+ try {
+ if(!core_stricmp("identify", argv[1]))
+ return identify(argc, argv);
+ else if(!core_stricmp("flopconvert", argv[1]))
+ return flopconvert(argc, argv);
+ else if(!core_stricmp("flopcreate", argv[1]))
+ return flopcreate(argc, argv);
+ else if(!core_stricmp("flopdir", argv[1]))
+ return flopdir(argc, argv);
+ else if(!core_stricmp("flopread", argv[1]))
+ return flopread(argc, argv);
+ else if(!core_stricmp("flopwrite", argv[1]))
+ return flopwrite(argc, argv);
+ else if(!core_stricmp("hddir", argv[1]))
+ return hddir(argc, argv);
+ else if(!core_stricmp("hdread", argv[1]))
+ return hdread(argc, argv);
+ else if(!core_stricmp("hdwrite", argv[1]))
+ return hdwrite(argc, argv);
+ else if (!core_stricmp("version", argv[1]))
+ return version(argc, argv);
+ else {
+ fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
+ display_usage(argv[0]);
+ return 1;
+ }
+ } catch(const std::exception &err) {
+ fprintf(stderr, "Error: %s\n", err.what());
return 1;
}
}