diff options
Diffstat (limited to 'src/tools/floptool.cpp')
-rw-r--r-- | src/tools/floptool.cpp | 815 |
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; } } |