summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/floptool.cpp
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2021-05-16 19:43:32 +0200
committer Olivier Galibert <galibert@pobox.com>2021-05-16 19:43:43 +0200
commit3afebb520a0217285bfc7ffc341cd5acbf7bd988 (patch)
tree464274565218e5f0a77423161ab2fb254bc9deab /src/tools/floptool.cpp
parent919468ac248764ffbac7737e109aba915654de97 (diff)
jasmin: Support write
Diffstat (limited to 'src/tools/floptool.cpp')
-rw-r--r--src/tools/floptool.cpp329
1 files changed, 276 insertions, 53 deletions
diff --git a/src/tools/floptool.cpp b/src/tools/floptool.cpp
index a3186b2374b..515ee3a87dd 100644
--- a/src/tools/floptool.cpp
+++ b/src/tools/floptool.cpp
@@ -275,6 +275,7 @@ static void display_usage()
fprintf(stderr, " floptool.exe flopcreate output_format filesystem <outputfile> -- Create a preformatted floppy image\n");
fprintf(stderr, " floptool.exe flopdir input_format filesystem <image> -- List the contents of a floppy image\n");
fprintf(stderr, " floptool.exe flopread input_format filesystem <image> <path> <outputfile> -- Extract a file from a floppy image\n");
+ fprintf(stderr, " floptool.exe flopwrite input_format filesystem <image> <inputfile> <path> -- Write a file into a floppy image\n");
}
static void display_formats()
@@ -456,11 +457,7 @@ static int create(int argc, char *argv[])
floppy_image image(84, 2, floppy_image::FF_UNKNOWN);
if(source_fs->m_type) {
- auto metav = source_fs->m_manager->volume_meta_description();
fs_meta_data meta;
- for(const auto &e : metav)
- if(!e.m_ro)
- meta[e.m_name] = e.m_default;
std::vector<u8> img(source_fs->m_image_size);
fsblk_vec_t blockdev(img);
@@ -514,10 +511,10 @@ static void dir_scan(u32 depth, filesystem_t::dir_t dir, std::vector<std::vector
auto subdir = dir.dir_get(c.m_key);
auto meta = subdir.metadata();
for(const auto &m : dmetad) {
- if(meta.find(m.m_name) == meta.end())
+ if(!meta.has(m.m_name))
continue;
size_t slot = nmap.find(m.m_name)->second;
- std::string val = fs_meta_to_string(m.m_type, meta.find(m.m_name)->second);
+ std::string val = fs_meta::to_string(m.m_type, meta.get(m.m_name));
if(slot == 0)
val = head + "dir " + val;
entries[id][slot] = val;
@@ -530,10 +527,10 @@ static void dir_scan(u32 depth, filesystem_t::dir_t dir, std::vector<std::vector
auto file = dir.file_get(c.m_key);
auto meta = file.metadata();
for(const auto &m : fmetad) {
- if(meta.find(m.m_name) == meta.end())
+ if(!meta.has(m.m_name))
continue;
size_t slot = nmap.find(m.m_name)->second;
- std::string val = fs_meta_to_string(m.m_type, meta.find(m.m_name)->second);
+ std::string val = fs_meta::to_string(m.m_type, meta.get(m.m_name));
if(slot == 0)
val = head + (c.m_type == fs_dir_entry_type::system_file ? "sys " : "file ") + val;
entries[id][slot] = val;
@@ -555,7 +552,7 @@ static int generic_dir(const filesystem_manager_t *fm, fsblk_t &blockdev)
if(!vmeta.empty()) {
std::string vinf = "Volume:";
for(const auto &e : vmetad)
- vinf += util::string_format(" %s=%s", fs_meta_get_name(e.m_name), fs_meta_to_string(e.m_type, vmeta[e.m_name]));
+ vinf += util::string_format(" %s=%s", fs_meta_data::entry_name(e.m_name), fs_meta::to_string(e.m_type, vmeta.get(e.m_name)));
printf("%s\n\n", vinf.c_str());
}
@@ -577,7 +574,7 @@ static int generic_dir(const filesystem_manager_t *fm, fsblk_t &blockdev)
entries.resize(1);
for(fs_meta_name n : names)
- entries[0].push_back(fs_meta_get_name(n));
+ entries[0].push_back(fs_meta_data::entry_name(n));
dir_scan(0, root, entries, nmap, names.size(), dmetad, fmetad);
@@ -694,31 +691,93 @@ static int hddir(int argc, char *argv[])
}
-
-
-static int generic_read(const filesystem_manager_t *fm, fsblk_t &blockdev, const char *srcpath, const char *dstpath)
+static std::vector<std::string> path_split(const filesystem_manager_t *fm, std::string path)
{
- auto load_fs = fm->mount(blockdev);
-
- std::string opath = srcpath;
- std::vector<std::string> path;
+ std::string opath = path;
+ std::vector<std::string> rpath;
if(fm->has_subdirectories()) {
std::string element;
char sep = fm->directory_separator();
for(char c : opath) {
if(c == sep) {
if(!element.empty()) {
- path.push_back(element);
+ rpath.push_back(element);
element.clear();
}
} else
element += c;
}
if(!element.empty())
- path.push_back(element);
+ rpath.push_back(element);
} else
- path.push_back(opath);
+ rpath.push_back(opath);
+
+ return rpath;
+}
+
+static std::vector<u8> fload(std::string path)
+{
+ char msg[4096];
+ sprintf(msg, "Error opening %s for reading", path.c_str());
+ auto fi = fopen(path.c_str(), "rb");
+ if (!fi) {
+ perror(msg);
+ exit(1);
+ }
+ fseek(fi, 0, SEEK_END);
+ long size = ftell(fi);
+ std::vector<u8> filedata(size);
+ fseek(fi, 0, SEEK_SET);
+ fread(filedata.data(), filedata.size(), 1, fi);
+ fclose(fi);
+
+ return filedata;
+}
+
+static void fsave(std::string path, const std::vector<u8> &data)
+{
+ char msg[4096];
+ sprintf(msg, "Error opening %s for writing", path.c_str());
+ auto fo = fopen(path.c_str(), "wb");
+ if (!fo) {
+ perror(msg);
+ exit(1);
+ }
+
+ fwrite(data.data(), data.size(), 1, fo);
+ fclose(fo);
+}
+
+static bool fexists(std::string path)
+{
+ auto f = fopen(path.c_str(), "rb");
+ if(f != nullptr) {
+ fclose(f);
+ return true;
+ }
+ return false;
+}
+
+
+static std::string path_make_rsrc(std::string path)
+{
+ auto p = path.end();
+ while(p != path.begin() && p[-1] != '/')
+ p--;
+ std::string rpath(path.begin(), p);
+ rpath += "._";
+ rpath += std::string(p, path.end());
+ return rpath;
+}
+
+
+
+static int generic_read(const filesystem_manager_t *fm, fsblk_t &blockdev, const char *srcpath, const char *dstpath)
+{
+ auto load_fs = fm->mount(blockdev);
+
+ std::vector<std::string> path = path_split(fm, srcpath);
auto dir = load_fs->root();
std::string apath;
@@ -752,43 +811,22 @@ static int generic_read(const filesystem_manager_t *fm, fsblk_t &blockdev, const
auto file = dir.file_get(c[j].m_key);
auto meta = file.metadata();
- if(meta.find(fs_meta_name::length) == meta.end()) {
+ if(!meta.has(fs_meta_name::length)) {
fprintf(stderr, "Error: %s%c%s is not a readable file\n", apath.c_str(), fm->directory_separator(), path.back().c_str());
return 1;
}
- auto filedata = file.read_all();
-
- char msg[4096];
- sprintf(msg, "Error opening %s for writing", dstpath);
- auto fo = fopen(dstpath, "wb");
- if (!fo) {
- perror(msg);
- return 1;
- }
-
- fwrite(filedata.data(), filedata.size(), 1, fo);
- fclose(fo);
+ fsave(dstpath, file.read_all());
- bool has_rsrc = fm->has_rsrc() && meta.find(fs_meta_name::rsrc_length) != meta.end();
+ bool has_rsrc = fm->has_rsrc() && meta.has(fs_meta_name::rsrc_length);
if(has_rsrc) {
- const char *d = dstpath + strlen(dstpath);
- while(d != dstpath && d[-1] != '/')
- d--;
- std::string dpath(dstpath, d);
- dpath += "._";
- dpath += d;
-
- sprintf(msg, "Error opening %s for writing", dstpath);
- auto fo = fopen(dpath.c_str(), "wb");
- if (!fo) {
- perror(msg);
- return 1;
- }
+ std::string rpath = path_make_rsrc(dstpath);
+
+ auto filedata = file.rsrc_read_all();
+ filedata.insert(filedata.begin(), 0x2a, 0);
- filedata = file.rsrc_read_all();
- u8 head[0x2a];
+ u8 *head = filedata.data();
filesystem_t::w32b(head+0x00, 0x00051607); // Magic
filesystem_t::w32b(head+0x04, 0x00020000); // Version
filesystem_t::fill(head+0x08, 0, 16); // Filler
@@ -797,9 +835,7 @@ static int generic_read(const filesystem_manager_t *fm, fsblk_t &blockdev, const
filesystem_t::w32b(head+0x22, 0x2a); // Offset in the file
filesystem_t::w32b(head+0x26, filedata.size()); // Length
- fwrite(head, 0x2a, 1, fo);
- fwrite(filedata.data(), filedata.size(), 1, fo);
- fclose(fo);
+ fsave(rpath, filedata);
}
return 0;
@@ -901,6 +937,189 @@ static int hdread(int argc, char *argv[])
}
+
+static int generic_write(const filesystem_manager_t *fm, fsblk_t &blockdev, const char *srcpath, const char *dstpath)
+{
+ auto load_fs = fm->mount(blockdev);
+
+ std::vector<std::string> path = path_split(fm, dstpath);
+
+ auto dir = load_fs->root();
+ std::string apath;
+ for(unsigned int i = 0; i < path.size() - 1; i++) {
+ auto c = dir.contents();
+ unsigned int j;
+ for(j = 0; j != c.size(); j++)
+ if(c[j].m_name == path[i])
+ break;
+ if(j == c.size()) {
+ fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fm->directory_separator(), path[i].c_str());
+ return 1;
+ }
+ if(c[j].m_type != fs_dir_entry_type::dir) {
+ fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fm->directory_separator(), path[i].c_str());
+ return 1;
+ }
+ dir = dir.dir_get(c[j].m_key);
+ apath += fm->directory_separator() + path[i];
+ }
+
+
+ fs_meta_data meta;
+ meta.set(fs_meta_name::name, path.back());
+
+ auto file = dir.file_create(meta);
+ auto filedata = fload(srcpath);
+ file.replace(filedata);
+
+ bool has_rsrc = fm->has_rsrc();
+
+ if(has_rsrc) {
+ std::string rpath = path_make_rsrc(dstpath);
+
+ if(fexists(rpath)) {
+ filedata = fload(rpath);
+ const u8 *head = filedata.data();
+
+ if(filesystem_t::r32b(head+0x00) == 0x00051607 &&
+ filesystem_t::r32b(head+0x04) == 0x00020000) {
+ u16 nent = filesystem_t::r16b(head+0x18);
+ for(u16 i=0; i != nent; i++) {
+ const u8 *e = head + 12*i;
+ if(filesystem_t::r32b(e+0) == 2) {
+ u32 start = filesystem_t::r32b(e+4);
+ u32 len = filesystem_t::r32b(e+8);
+ filedata.erase(filedata.begin(), filedata.begin() + start);
+ filedata.erase(filedata.begin() + len, filedata.end());
+ file.rsrc_replace(filedata);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int flopwrite(int argc, char *argv[])
+{
+ if (argc!=7) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage();
+ return 1;
+ }
+
+ auto format = find_format_by_name(argv[2]);
+ if(!format) {
+ fprintf(stderr, "Error: Format '%s' unknown\n", argv[2]);
+ return 1;
+ }
+
+ auto fs = find_fs_by_name(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[2]);
+ return 1;
+ }
+
+ char msg[4096];
+ sprintf(msg, "Error opening %s for reading", argv[4]);
+ FILE *f = fopen(argv[4], "rb");
+ if (!f) {
+ perror(msg);
+ return 1;
+ }
+ io_generic io;
+ io.file = f;
+ io.procs = &stdio_ioprocs_noclose;
+ io.filler = 0xff;
+
+ floppy_image image(84, 2, floppy_image::FF_UNKNOWN);
+ if(!format->load(&io, floppy_image::FF_UNKNOWN, variants, &image)) {
+ fprintf(stderr, "Error: parsing input file as '%s' failed\n", format->name());
+ return 1;
+ }
+
+ std::vector<u8> img;
+ auto iog = ram_open(img);
+ auto load_format = fs->m_type();
+ load_format->save(iog, variants, &image);
+
+ fsblk_vec_t blockdev(img);
+ generic_write(fs->m_manager, blockdev, argv[5], argv[6]);
+
+ load_format->load(iog, image.get_form_factor(), variants, &image);
+ delete load_format;
+ delete iog;
+
+ sprintf(msg, "Error oapening %s for writing", argv[4]);
+ f = fopen(argv[4], "wb");
+ if (!f) {
+ perror(msg);
+ return 1;
+ }
+
+ io_generic dest_io;
+ dest_io.file = f;
+ dest_io.procs = &stdio_ioprocs_noclose;
+ dest_io.filler = 0xff;
+
+ if(!format->save(&dest_io, variants, &image)) {
+ fprintf(stderr, "Error: writing output file as '%s' failed\n", format->name());
+ return 1;
+ }
+
+ fclose((FILE *)dest_io.file);
+ return 0;
+}
+
+
+// Should use chd&friends instead, but one thing at a time
+
+static int hdwrite(int argc, char *argv[])
+{
+ if (argc!=6) {
+ fprintf(stderr, "Incorrect number of arguments.\n\n");
+ display_usage();
+ return 1;
+ }
+
+ auto fs = find_fs_by_name(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;
+ }
+
+ char msg[4096];
+ sprintf(msg, "Error opening %s for reading", argv[3]);
+ FILE *f = fopen(argv[3], "rb");
+ if (!f) {
+ perror(msg);
+ return 1;
+ }
+ fseek(f, 0, SEEK_END);
+ size_t size = ftell(f);
+ rewind(f);
+ std::vector<u8> img(size);
+ fread(img.data(), size, 1, f);
+ fclose(f);
+
+ fsblk_vec_t blockdev(img);
+ return generic_write(fs->m_manager, blockdev, argv[4], argv[5]);
+}
+
+
int CLIB_DECL main(int argc, char *argv[])
{
init_formats();
@@ -915,16 +1134,20 @@ int CLIB_DECL main(int argc, char *argv[])
return identify(argc, argv);
else if (!core_stricmp("convert", argv[1]))
return convert(argc, argv);
- else if (!core_stricmp("create", argv[1]))
+ else if (!core_stricmp("flopcreate", argv[1]))
return create(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 {
fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
display_usage();