diff options
author | 2021-05-16 19:43:32 +0200 | |
---|---|---|
committer | 2021-05-16 19:43:43 +0200 | |
commit | 3afebb520a0217285bfc7ffc341cd5acbf7bd988 (patch) | |
tree | 464274565218e5f0a77423161ab2fb254bc9deab /src/tools/floptool.cpp | |
parent | 919468ac248764ffbac7737e109aba915654de97 (diff) |
jasmin: Support write
Diffstat (limited to 'src/tools/floptool.cpp')
-rw-r--r-- | src/tools/floptool.cpp | 329 |
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(); |