/*************************************************************************** main.c Imgtool command line front end ***************************************************************************/ #include #include #include #include #include #include #include "imgtool.h" #include "utils.h" #include "mess.h" #include "main.h" #include "fileio.h" #include "modules.h" /* ---------------------------------------------------------------------- */ static void writeusage(FILE *f, int write_word_usage, struct command *c, char *argv[]) { fprintf(f, "%s %s %s %s\n", (write_word_usage ? "Usage:" : " "), osd_basename(argv[0]), c->name, c->usage ? c->usage : ""); } /* ----------------------------------------------------------------------- */ static int parse_options(int argc, char *argv[], int minunnamed, int maxunnamed, option_resolution *resolution, filter_getinfoproc *filter, const char **fork) { int i; int lastunnamed = 0; char *s; char *name = NULL; char *value = NULL; optreserr_t oerr; static char buf[256]; if (filter) *filter = NULL; if (fork) *fork = NULL; for (i = 0; i < argc; i++) { /* Named or unamed arg */ if ((argv[i][0] != '-') || (argv[i][1] != '-')) { /* Unnamed */ if (i >= maxunnamed) goto error; /* Too many unnamed */ lastunnamed = i + 1; } else { /* Named */ name = argv[i] + 2; s = strchr(name, '='); if (!s) goto error; *s = 0; value = s + 1; if (!strcmp(name, "filter")) { /* filter option */ if (!filter) goto error; /* this command doesn't use filters */ if (*filter) goto optionalreadyspecified; *filter = filter_lookup(value); if (!(*filter)) goto filternotfound; } else if (!strcmp(name, "fork")) { /* fork option */ if (!fork) goto error; /* this command doesn't use filters */ if (*fork) goto optionalreadyspecified; snprintf(buf, sizeof(buf) / sizeof(buf[0]), "%s", value); *fork = buf; } else { /* Other named option */ if (i < minunnamed) goto error; /* Too few unnamed */ oerr = option_resolution_add_param(resolution, name, value); if (oerr) goto opterror; } } } return lastunnamed; filternotfound: fprintf(stderr, "%s: Unknown filter type\n", value); return -1; optionalreadyspecified: fprintf(stderr, "Cannot specify multiple %ss\n", name); return -1; opterror: fprintf(stderr, "%s: %s\n", name, option_resolution_error_string(oerr)); return -1; error: fprintf(stderr, "%s: Unrecognized option\n", argv[i]); return -1; } void reporterror(imgtoolerr_t err, const struct command *c, const char *format, const char *imagename, const char *filename, const char *newname, option_resolution *opts) { const char *src = "imgtool"; const char *err_name; err_name = imgtool_error(err); switch(ERRORSOURCE(err)) { case IMGTOOLERR_SRC_MODULE: src = format; break; case IMGTOOLERR_SRC_FUNCTIONALITY: src = c->name; break; case IMGTOOLERR_SRC_IMAGEFILE: src = imagename; break; case IMGTOOLERR_SRC_FILEONIMAGE: src = filename; break; case IMGTOOLERR_SRC_NATIVEFILE: src = newname ? newname : filename; break; } fflush(stdout); fflush(stderr); if (!src) src = c->name; fprintf(stderr, "%s: %s\n", src, err_name); } static const char *interpret_filename(const char *filename) { if (!strcmp(filename, "??BOOT??") || !strcmp(filename, "\'??BOOT??\'") || !strcmp(filename, "\"??BOOT??\"")) filename = FILENAME_BOOTBLOCK; return filename; } /* ----------------------------------------------------------------------- */ static int cmd_dir(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; int total_count, total_size, freespace_err; UINT64 freespace; imgtool_image *image = NULL; imgtool_partition *partition = NULL; imgtool_directory *imgenum = NULL; imgtool_dirent ent; char buf[512]; const char *path; int partition_index = 0; /* attempt to open image */ err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); if (err) goto done; /* attempt to open partition */ err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; path = argc > 2 ? argv[2] : NULL; err = imgtool_directory_open(partition, path, &imgenum); if (err) goto done; memset(&ent, 0, sizeof(ent)); total_count = 0; total_size = 0; fprintf(stdout, "Contents of %s:\n", argv[1]); imgtool_image_info(image, buf, sizeof(buf)); if (buf[0]) fprintf(stdout, "%s\n", buf); fprintf(stdout, "------------------------ ------ ---------------\n"); while (((err = imgtool_directory_get_next(imgenum, &ent)) == 0) && !ent.eof) { if (ent.directory) snprintf(buf, sizeof(buf), ""); else snprintf(buf, sizeof(buf), "%u", (unsigned int) ent.filesize); fprintf(stdout, "%-20s\t%8s %15s\n", ent.filename, buf, ent.attr); total_count++; total_size += ent.filesize; } freespace_err = imgtool_partition_get_free_space(partition, &freespace); if (err) goto done; fprintf(stdout, "------------------------ ------ ---------------\n"); fprintf(stdout, "%8i File(s) %8i bytes\n", total_count, total_size); if (!freespace_err) fprintf(stdout, " %8u bytes free\n", (unsigned int) freespace); done: if (imgenum) imgtool_directory_close(imgenum); if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (err) reporterror(err, c, argv[0], argv[1], NULL, NULL, NULL); return err ? -1 : 0; } static int cmd_get(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *image = NULL; imgtool_partition *partition = NULL; const char *filename; char *new_filename; int unnamedargs = 0; filter_getinfoproc filter; const char *fork; int partition_index = 0; err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); if (err) goto done; err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; filename = interpret_filename(argv[2]); unnamedargs = parse_options(argc, argv, 3, 4, NULL, &filter, &fork); if (unnamedargs < 0) goto done; new_filename = (unnamedargs == 4) ? argv[3] : NULL; err = imgtool_partition_get_file(partition, filename, fork, new_filename, filter); if (err) goto done; err = IMGTOOLERR_SUCCESS; done: if (err) reporterror(err, c, argv[0], argv[1], argv[2], argv[3], NULL); if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); return (err || (unnamedargs < 0)) ? -1 : 0; } static int cmd_put(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err = IMGTOOLERR_SUCCESS; int i; imgtool_image *image = NULL; imgtool_partition *partition = NULL; const char *filename = NULL; int unnamedargs; filter_getinfoproc filter; const imgtool_module *module; option_resolution *resolution = NULL; const char *fork; const char *new_filename; char **filename_list; int filename_count; int partition_index = 0; const struct OptionGuide *writefile_optguide; const char *writefile_optspec; module = imgtool_find_module(argv[0]); if (!module) { err = IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE; goto done; } /* ugh I hate the way this function is set up, this is because the * arguments depend on the partition; something that requires some * rudimentary parsing */ if (argc >= 2) { /* open up the image */ err = imgtool_image_open(module, argv[1], OSD_FOPEN_RW, &image); if (err) goto done; /* open up the partition */ err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; writefile_optguide = (const struct OptionGuide *) imgtool_partition_get_info_ptr(partition, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); writefile_optspec = imgtool_partition_get_info_ptr(partition, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); if (writefile_optguide && writefile_optspec) { resolution = option_resolution_create(writefile_optguide, writefile_optspec); if (!resolution) { err = IMGTOOLERR_OUTOFMEMORY; goto done; } } } unnamedargs = parse_options(argc, argv, 4, 0xffff, resolution, &filter, &fork); if (unnamedargs < 0) return -1; /* pick out which args are filenames, and which one is the destination */ new_filename = interpret_filename(argv[unnamedargs - 1]); filename_list = &argv[2]; filename_count = unnamedargs - 3; /* loop through the filenames, and put them */ for (i = 0; i < filename_count; i++) { filename = filename_list[i]; printf("Putting file '%s'...\n", filename); err = imgtool_partition_put_file(partition, new_filename, fork, filename, resolution, filter); if (err) goto done; } done: if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (resolution) option_resolution_close(resolution); if (err) reporterror(err, c, argv[0], argv[1], filename, NULL, resolution); return err ? -1 : 0; } static int cmd_getall(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *image = NULL; imgtool_partition *partition = NULL; imgtool_directory *imgenum = NULL; imgtool_dirent ent; filter_getinfoproc filter; int unnamedargs; const char *path = NULL; int arg; int partition_index = 0; err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &image); if (err) goto done; err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; arg = 2; if ((argc > 2) && (argv[2][0] != '-')) { path = argv[arg++]; } unnamedargs = parse_options(argc, argv, arg, arg, NULL, &filter, NULL); if (unnamedargs < 0) goto done; err = imgtool_directory_open(partition, path, &imgenum); if (err) goto done; memset(&ent, 0, sizeof(ent)); while (((err = imgtool_directory_get_next(imgenum, &ent)) == 0) && !ent.eof) { fprintf(stdout, "Retrieving %s (%u bytes)\n", ent.filename, (unsigned int) ent.filesize); err = imgtool_partition_get_file(partition, ent.filename, NULL, NULL, filter); if (err) goto done; } done: if (imgenum) imgtool_directory_close(imgenum); if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (err) reporterror(err, c, argv[0], argv[1], NULL, NULL, NULL); return err ? -1 : 0; } static int cmd_del(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *image = NULL; imgtool_partition *partition = NULL; int partition_index = 0; err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); if (err) goto done; err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; err = imgtool_partition_delete_file(partition, argv[2]); if (err) goto done; done: if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (err) reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); return err ? -1 : 0; } static int cmd_mkdir(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *image = NULL; imgtool_partition *partition = NULL; int partition_index = 0; err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); if (err) goto done; err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; err = imgtool_partition_create_directory(partition, argv[2]); if (err) goto done; done: if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (err) reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); return err ? -1 : 0; } static int cmd_rmdir(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *image = NULL; imgtool_partition *partition = NULL; int partition_index = 0; err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &image); if (err) goto done; err = imgtool_partition_open(image, partition_index, &partition); if (err) goto done; err = imgtool_partition_delete_directory(partition, argv[2]); if (err) goto done; done: if (partition) imgtool_partition_close(partition); if (image) imgtool_image_close(image); if (err) reporterror(err, c, argv[0], argv[1], argv[2], NULL, NULL); return err ? -1 : 0; } static int cmd_identify(const struct command *c, int argc, char *argv[]) { imgtool_module *modules[128]; imgtoolerr_t err; int i; err = imgtool_identify_file(argv[0], modules, sizeof(modules) / sizeof(modules[0])); if (err) goto error; for (i = 0; modules[i]; i++) { printf("%.16s %s\n", modules[i]->name, modules[i]->description); } return 0; error: reporterror(err, c, NULL, argv[0], NULL, NULL, 0); return -1; } static int cmd_create(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; int unnamedargs; const imgtool_module *module; option_resolution *resolution = NULL; module = imgtool_find_module(argv[0]); if (!module) { err = IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE; goto error; } if (module->createimage_optguide && module->createimage_optspec) { resolution = option_resolution_create(module->createimage_optguide, module->createimage_optspec); if (!resolution) { err = IMGTOOLERR_OUTOFMEMORY; goto error; } } unnamedargs = parse_options(argc, argv, 2, 3, resolution, NULL, NULL); if (unnamedargs < 0) return -1; err = imgtool_image_create(module, argv[1], resolution, NULL); if (err) goto error; if (resolution) option_resolution_close(resolution); return 0; error: if (resolution) option_resolution_close(resolution); reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); return -1; } static int cmd_readsector(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *img; imgtool_stream *stream = NULL; void *buffer = NULL; UINT32 size, track, head, sector; /* attempt to open image */ err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_READ, &img); if (err) goto done; track = atoi(argv[2]); head = atoi(argv[3]); sector = atoi(argv[4]); err = imgtool_image_get_sector_size(img, track, head, sector, &size); if (err) goto done; buffer = malloc(size); if (!buffer) { err = IMGTOOLERR_OUTOFMEMORY; goto done; } err = imgtool_image_read_sector(img, track, head, sector, buffer, size); if (err) goto done; stream = stream_open(argv[5], OSD_FOPEN_WRITE); if (!stream) { err = IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE; goto done; } stream_write(stream, buffer, size); done: if (buffer) free(buffer); if (stream) stream_close(stream); if (err) reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); return err ? -1 : 0; } static int cmd_writesector(const struct command *c, int argc, char *argv[]) { imgtoolerr_t err; imgtool_image *img; imgtool_stream *stream = NULL; void *buffer = NULL; UINT32 size, track, head, sector; /* attempt to open image */ err = imgtool_image_open_byname(argv[0], argv[1], OSD_FOPEN_RW, &img); if (err) goto done; track = atoi(argv[2]); head = atoi(argv[3]); sector = atoi(argv[4]); stream = stream_open(argv[5], OSD_FOPEN_READ); if (!stream) { err = IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE; goto done; } size = (UINT32) stream_size(stream); buffer = malloc(size); if (!buffer) { err = IMGTOOLERR_OUTOFMEMORY; goto done; } stream_read(stream, buffer, size); err = imgtool_image_write_sector(img, track, head, sector, buffer, size); if (err) goto done; done: if (buffer) free(buffer); if (stream) stream_close(stream); if (err) reporterror(err, c, argv[0], argv[1], NULL, NULL, 0); return err ? -1 : 0; } static int cmd_listformats(const struct command *c, int argc, char *argv[]) { const imgtool_module *mod; fprintf(stdout, "Image formats supported by imgtool:\n\n"); mod = imgtool_find_module(NULL); while(mod) { fprintf(stdout, " %-25s%s\n", mod->name, mod->description); mod = mod->next; } return 0; } static int cmd_listfilters(const struct command *c, int argc, char *argv[]) { int i; fprintf(stdout, "Filters supported by imgtool:\n\n"); for (i = 0; filters[i]; i++) { fprintf(stdout, " %-11s%s\n", filter_get_info_string(filters[i], FILTINFO_STR_NAME), filter_get_info_string(filters[i], FILTINFO_STR_HUMANNAME)); } return 0; } static void listoptions(const struct OptionGuide *opt_guide, const char *opt_spec) { char opt_name[32]; const char *opt_desc; struct OptionRange range[32]; char range_buffer[512]; char buf[32]; int i; assert(opt_guide); fprintf(stdout, "Option Allowed values Description\n"); fprintf(stdout, "---------------- ------------------------------ -----------\n"); while(opt_guide->option_type != OPTIONTYPE_END) { range_buffer[0] = 0; snprintf(opt_name, sizeof(opt_name) / sizeof(opt_name[0]), "--%s", opt_guide->identifier); opt_desc = opt_guide->display_name; /* is this option relevant? */ if (!strchr(opt_spec, opt_guide->parameter)) { opt_guide++; continue; } switch(opt_guide->option_type) { case OPTIONTYPE_INT: option_resolution_listranges(opt_spec, opt_guide->parameter, range, sizeof(range) / sizeof(range[0])); for (i = 0; range[i].max >= 0; i++) { snprintf(buf, sizeof(buf) / sizeof(buf[0]), (range[i].min == range[i].max) ? "%i" : "%i-%i", range[i].min, range[i].max); if (i > 0) strncatz(range_buffer, "/", sizeof(range_buffer)); strncatz(range_buffer, buf, sizeof(range_buffer)); } break; case OPTIONTYPE_ENUM_BEGIN: i = 0; while(opt_guide[1].option_type == OPTIONTYPE_ENUM_VALUE) { if (i > 0) strncatz(range_buffer, "/", sizeof(range_buffer)); strncatz(range_buffer, opt_guide[1].identifier, sizeof(range_buffer)); opt_guide++; i++; } break; case OPTIONTYPE_STRING: snprintf(range_buffer, sizeof(range_buffer), "(string)"); break; default: assert(0); break; } fprintf(stdout, "%16s %-30s %s\n", opt_name, range_buffer, opt_desc); opt_guide++; } } static int cmd_listdriveroptions(const struct command *c, int argc, char *argv[]) { const imgtool_module *mod; const struct OptionGuide *opt_guide; const char *opt_spec; mod = imgtool_find_module(argv[0]); if (!mod) goto error; fprintf(stdout, "Driver specific options for module '%s':\n\n", argv[0]); /* list write options */ opt_guide = (const struct OptionGuide *) imgtool_get_info_ptr(&mod->imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); opt_spec = imgtool_get_info_string(&mod->imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC); if (opt_guide) { fprintf(stdout, "Image specific file options (usable on the 'put' command):\n\n"); listoptions(opt_guide, opt_spec); puts("\n"); } else { fprintf(stdout, "No image specific file options\n\n"); } /* list create options */ opt_guide = mod->createimage_optguide; if (opt_guide) { fprintf(stdout, "Image specific creation options (usable on the 'create' command):\n\n"); listoptions(opt_guide, mod->createimage_optspec); puts("\n"); } else { fprintf(stdout, "No image specific creation options\n\n"); } return 0; error: reporterror(IMGTOOLERR_MODULENOTFOUND|IMGTOOLERR_SRC_MODULE, c, argv[0], NULL, NULL, NULL, NULL); return -1; } /* ----------------------------------------------------------------------- */ static struct command cmds[] = { { "create", cmd_create, " [--(createoption)=value]", 2, 8, 0}, { "dir", cmd_dir, " [path]", 2, 3, 0 }, { "get", cmd_get, " [newname] [--filter=filter] [--fork=fork]", 3, 4, 0 }, { "put", cmd_put, " ... [--(fileoption)==value] [--filter=filter] [--fork=fork]", 3, 0xffff, 0 }, { "getall", cmd_getall, " [path] [--filter=filter]", 2, 3, 0 }, { "del", cmd_del, " ...", 3, 3, 1 }, { "mkdir", cmd_mkdir, " ", 3, 3, 0 }, { "rmdir", cmd_rmdir, " ...", 3, 3, 1 }, { "readsector", cmd_readsector, " ", 6, 6, 0 }, { "writesector", cmd_writesector, " ", 6, 6, 0 }, { "identify", cmd_identify, "", 1, 1 }, { "listformats", cmd_listformats, NULL, 0, 0, 0 }, { "listfilters", cmd_listfilters, NULL, 0, 0, 0 }, { "listdriveroptions", cmd_listdriveroptions, "", 1, 1, 0 } }; #ifdef WIN32 #include "glob.h" void win_expand_wildcards(int *argc, char **argv[]) { int i; glob_t g; memset(&g, 0, sizeof(g)); for (i = 0; i < *argc; i++) glob((*argv)[i], (g.gl_pathc > 0) ? GLOB_APPEND|GLOB_NOCHECK : GLOB_NOCHECK, NULL, &g); *argc = g.gl_pathc; *argv = g.gl_pathv; } #endif #ifdef WIN32 int CLIB_DECL utf8_main(int argc, char *argv[]) #else int CLIB_DECL main(int argc, char *argv[]) #endif { int i; int result; struct command *c; const char *sample_format = "coco_jvc_rsdos"; #ifdef MAME_DEBUG if (imgtool_validitychecks()) return -1; #endif /* MAME_DEBUG */ #ifdef WIN32 win_expand_wildcards(&argc, &argv); #endif putchar('\n'); if (argc > 1) { /* figure out what command they are running, and run it */ for (i = 0; i < (sizeof(cmds) / sizeof(cmds[0])); i++) { c = &cmds[i]; if (!mame_stricmp(c->name, argv[1])) { /* check argument count */ if (c->minargs > (argc - 2)) goto cmderror; /* initialize the imgtool core */ imgtool_init(TRUE, NULL); if (c->lastargrepeats && (argc > c->maxargs)) { for (i = c->maxargs+1; i < argc; i++) { argv[c->maxargs+1] = argv[i]; result = c->cmdproc(c, c->maxargs, argv + 2); if (result) goto done; } result = 0; goto done; } else { if ((c->maxargs > 0) && (c->maxargs < (argc - 2))) goto cmderror; result = c->cmdproc(c, argc - 2, argv + 2); goto done; } } } } /* Usage */ fprintf(stderr, "imgtool - Generic image manipulation tool for use with MESS\n\n"); for (i = 0; i < (sizeof(cmds) / sizeof(cmds[0])); i++) { writeusage(stdout, (i == 0), &cmds[i], argv); } fprintf(stderr, "\n is the image format, e.g. %s\n", sample_format); fprintf(stderr, " is the image filename; can specify a ZIP file for image name\n"); fprintf(stderr, "\nExample usage:\n"); fprintf(stderr, "\t%s dir %s myimageinazip.zip\n", osd_basename(argv[0]), sample_format); fprintf(stderr, "\t%s get %s myimage.dsk myfile.bin mynewfile.txt\n", osd_basename(argv[0]), sample_format); fprintf(stderr, "\t%s getall %s myimage.dsk\n", osd_basename(argv[0]), sample_format); result = 0; goto done; cmderror: writeusage(stdout, 1, &cmds[i], argv); result = -1; done: imgtool_exit(); return result; }