slbldtls/res2c.c

186 lines
6.7 KiB
C
Raw Permalink Normal View History

#include <stdio.h>
#include <stddef.h>
#include <string.h>
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 <filename>] [--allowempty] [--nofunctions] [--defaulttype <name>] [--loadfunction <functionname>] [--registerfunction <functionname>] [[--type <typestring>] [--arrayname <name>] [--filename <name>] resource1 [[--type <typestring>] [--arrayname <name>] [--filename <name>] 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 <name> 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 <name> 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);
}
}