186 lines
6.7 KiB
C
186 lines
6.7 KiB
C
#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);
|
|
}
|
|
}
|