#include #include #include int usage(int argc, char** argv, int argerr, const char* error) { FILE* o = error ? stderr : stdout; char* progname = argv[0]; fprintf(o, "This program '%s' loads arbitrary files and outputs them as C code which loads them in the style of 'program resources'.\n", progname); fprintf(o, "It is particularly designed for loading one or more ramdisks, init programs or other arbitrary 'blobs' in kernel boot images.\n\n"); fprintf(o, "By default it will produce a function which calls another function to register each resource.\n"); fprintf(o, "Using the --nofunctions option and setting the name with --arrayname you can also get it to just produce arrays similar to a simple 'bin2c' program.\n\n"); fprintf(o, "USAGE:\n"); fprintf(o, " %s [--output ] [--allowempty] [--nofunctions] [--defaulttype ] [--loadfunction ] [--registerfunction ] [[--type ] [--arrayname ] [--filename ] resource1 [[--type ] [--arrayname ] [--filename ] resource2 [...]]]\n\n", progname); fprintf(o, "EXAMPLES:\n"); fprintf(o, " %s --output gamemods_autogenerated.c --loadfunction mods_init --allowempty --defaulttype GAME_MOD *.mod\n\n", progname); fprintf(o, " %s --output mybootscripts.c --type SCRIPT --name bootscript startup.script --type RAMDISK --name initramdisk startup.image\n\n", progname); fprintf(o, " %s --allowempty\n\n", progname); return error == NULL ? 0 : -1; } #define MAX_RESOURCES 100 FILE* files[MAX_RESOURCES]; char* types[MAX_RESOURCES]; char* arraynames[MAX_RESOURCES]; char* filenames[MAX_RESOURCES]; unsigned long sizes[MAX_RESOURCES]; unsigned char buffer[256]; int main(int argc, char** argv) { char* defaulttype = "RESOURCE"; char* nexttype = NULL; char* nextarrayname = NULL; char* nextfilename = NULL; int nresources = 0; int allowempty = 0; int nofunctions = 0; char* loadfunction = "resources_init"; char* registerfunction = "resources_register"; char* progname = argv[0]; int bytesperline = 16; char* outputname = NULL; char simplenamebuff[6]; simplenamebuff[0] = '_'; simplenamebuff[1] = 'r'; simplenamebuff[2] = 'e'; simplenamebuff[3] = 's'; simplenamebuff[5] = 0; int argi = 1; while (argi < argc) { if (!strcmp(argv[argi], "--usage")) { usage(argc, argv, argi, NULL); return 0; } else if (!strcmp(argv[argi], "--type")) { if (argi + 1 >= argc) { return usage(argc, argv, argi, "Missing argument after --type"); } argi++; nexttype = argv[argi]; } else if (!strcmp(argv[argi], "--arrayname")) { if (argi + 1 >= argc) { return usage(argc, argv, argi, "Missing argument after --arrayname"); } argi++; nextarrayname = argv[argi]; } else if (!strcmp(argv[argi], "--filename")) { if (argi + 1 >= argc) { return usage(argc, argv, argi, "Missing argument after --filename"); } argi++; nextfilename = argv[argi]; } else if (!strcmp(argv[argi], "--output") || (argv[argi][0] == '-' && argv[argi][1] == 'o' && argv[argi][2] == 0)) { if (outputname != NULL) { usage(argc, argv, argi, "Can't specify output more than once"); return -1; } if (argi + 1 >= argc) { usage(argc, argv, argi, "Missing argument after --output"); return -1; } argi++; outputname = argv[argi]; } else if (argv[argi][0] == '-' && argv[argi][1] == 'o') { if (outputname != NULL) { usage(argc, argv, argi, "Can't specify output more than once"); return -1; } outputname = argv[argi]+2; } else if (!strcmp(argv[argi], "--allowempty")) { allowempty = 1; } else if (!strcmp(argv[argi], "--nofunctions")) { nofunctions = 1; } else { if (nresources + 1 >= MAX_RESOURCES) { return usage(argc, argv, argi, "Too many resources"); } files[nresources] = fopen(argv[argi], "rb"); if (nexttype) { types[nresources] = nexttype; nexttype = NULL; } else { types[nresources] = defaulttype; } if (nextarrayname) { arraynames[nresources] = nextarrayname; nextarrayname = NULL; } else { simplenamebuff[4] = (char)('A' + nresources); arraynames[nresources] = strdup(simplenamebuff); } if (nextfilename) { filenames[nresources] = nextfilename; nextfilename = NULL; } else { char* lastsegment = argv[argi]; char* s = lastsegment; while (*s) { if (*s == '/' || *s == '\\' || *s == ':') { lastsegment = s+1; } s++; } filenames[nresources] = lastsegment; } nresources++; } argi++; } if (nresources < 1 && !allowempty) { return usage(argc, argv, argi, "Expected some resources to add or --allowempty to allow an empty resource structure"); } FILE* output = stdout; if (outputname != NULL) { output = fopen(outputname, "w"); if (output == NULL) { fprintf(stderr, "ERROR: Failed to open output file '%s'\n", outputname); return -1; } } fprintf(output, "// This file is autogenerated by '%s'\n\n", progname); char* hex = "0123456789ABCDEF"; for (int resi = 0; resi < nresources; resi++) { FILE* f = files[resi]; unsigned long sz = 0; size_t nread; fprintf(output, "unsigned char %s[] = {\n", arraynames[resi]); while ((nread = fread(buffer, 1, bytesperline, f)) > 0) { if (sz > 0) { fprintf(output, ",\n"); } sz += (unsigned long) nread; for (size_t bytei = 0; bytei < nread; bytei++) { int b = ((int) buffer[bytei]) & 0xFF; fprintf(output, "%s0x%c%c", bytei > 0 ? ", " : " ", hex[b>>4], hex[b&0xF]); } } fprintf(output, "\n}; // end of %s\n\n", arraynames[resi]); sizes[resi] = sz; fclose(f); } if (!nofunctions) { fprintf(output, "// This function should be implemented in the program code, the name can be changed with using --registerfunction when generating this code\n"); fprintf(output, "void %s(const char* type, const char* name, unsigned char* data, unsigned long size);\n\n", registerfunction); fprintf(output, "// This function should be invoked from the program code, the name can be changed with using --loadfunction when generating this code\n"); fprintf(output, "void %s() {\n", loadfunction); for (int resi = 0; resi < nresources; resi++) { fprintf(output, " %s(\"%s\", \"%s\", %s, %lu);\n", registerfunction, types[resi], filenames[resi], arraynames[resi], sizes[resi]); } fprintf(output, "}\n\n"); } if (outputname != NULL) { fclose(output); } }