/*
Copyright:
(C) 2022-2023 Daniele 'dzonerzy' Linguaglossa - http://libdzonerzy.so
This file is part of libdzonerzy.so.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
*/
#define _POSIX_C_SOURCE 200809L
#include
#include
#include
#include
#include
#include
#define VERSION "0.0.1"
typedef struct _embed
{
char *input;
char *output;
char *format;
int verbose;
int quiet;
int autowrap;
} embed_t;
static void usage(char **argv);
static void version(char **argv);
static int embed(embed_t *args);
static char *clean_filename(char *filename);
int main(int argc, char **argv)
{
int c = 0;
embed_t args = {0};
while ((c = getopt(argc, argv, "hvi:o:f:Vqw")) != -1)
{
switch (c)
{
case 'h':
usage(argv);
exit(EXIT_SUCCESS);
break;
case 'v':
version(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
args.input = optarg;
break;
case 'o':
args.output = optarg;
break;
case 'f':
// check -f=c -f=h handle equal sign and skip it
if (optarg[0] == '=')
{
optarg++;
}
switch (optarg[0])
{
case 'c':
args.format = "c";
break;
case 'h':
args.format = "h";
break;
default:
usage(argv);
exit(EXIT_FAILURE);
break;
}
break;
case 'V':
args.verbose = 1;
break;
case 'q':
args.quiet = 1;
break;
case 'w':
args.autowrap = 1;
break;
default:
usage(argv);
exit(EXIT_FAILURE);
break;
}
}
return embed(&args);
}
void usage(char **argv)
{
char *name = strrchr(argv[0], '/');
if (name == NULL)
{
name = argv[0];
}
else
{
name++;
}
printf("Usage: %s [OPTIONS]\n", name);
printf("Embed a file into a C source file.\n");
printf("\n");
printf("Options:\n");
printf(" -h, --help Print this help and exit\n");
printf(" -v, --version Print version and exit\n");
printf(" -i, --input=FILE Input file\n");
printf(" -o, --output=FILE Output file\n");
printf(" -f, --format=FORMAT Output format (c, h)\n");
printf(" -V, --verbose Verbose output\n");
printf(" -q, --quiet Quiet output\n");
printf("\n");
}
void version(char **argv)
{
char *name = strrchr(argv[0], '/');
if (name == NULL)
{
name = argv[0];
}
else
{
name++;
}
printf("%s version %s\n", name, VERSION);
printf("\n");
}
char *clean_filename(char *filename)
{
char *p = filename;
while (*p)
{
// replace with _
// replace symbols with _
// replace - with _
// replace . with _
// all characters to uppercase
switch (*p)
{
case ' ':
case '-':
case '.':
case '/':
case '\\':
case ':':
case ';':
case ',':
case '\'':
case '"':
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
case '<':
case '>':
case '?':
case '!':
case '@':
case '#':
case '$':
case '%':
case '^':
case '&':
case '*':
case '+':
case '=':
case '|':
case '`':
case '~':
*p = '_';
break;
default:
*p = toupper(*p);
break;
}
p++;
}
return filename;
}
int embed(embed_t *args)
{
if (args->input == NULL)
{
fprintf(stderr, "Input file not specified\n");
return EXIT_FAILURE;
}
if (args->format == NULL)
{
fprintf(stderr, "Output format not specified\n");
return EXIT_FAILURE;
}
if (args->verbose)
{
printf("Input file: %s\n", args->input);
printf("Output file: %s\n", args->output);
printf("Output format: %s\n", args->format);
}
FILE *input = fopen(args->input, "rb");
if (input == NULL)
{
if (!args->quiet)
fprintf(stderr, "Unable to open input file: %s\n", args->input);
return EXIT_FAILURE;
}
FILE *output = NULL;
if (args->output != NULL)
{
output = fopen(args->output, "w");
}
else
{
output = stdout;
}
char *name_only = strdup(args->input);
name_only = strrchr(name_only, '/');
if (name_only == NULL)
{
name_only = args->input;
}
else
{
name_only++;
}
char *input_name = strdup(args->input);
input_name = strrchr(input_name, '/');
if (input_name == NULL)
{
input_name = args->input;
}
else
{
input_name++;
}
input_name = clean_filename(input_name);
fprintf(output, "/*\n");
fprintf(output, " * This file was automatically generated by embed - DO NOT EDIT\n");
fprintf(output, " * https://libdzonerzy.so\n");
fprintf(output, " */\n");
fprintf(output, "\n");
if (args->format[0] == 'c')
{
if (args->autowrap)
{
fprintf(output, "__attribute__((section(\"embed/%s\"))) const unsigned char %s[] = {\n", name_only, input_name);
}
else
{
fprintf(output, "__attribute__((section(\"embed/%s\"))) const unsigned char %s[] = {", name_only, input_name);
}
}
else if (args->format[0] == 'h')
{
fprintf(output, "#pragma once\n");
fprintf(output, "#ifndef %s_H\n", input_name);
if (args->autowrap)
{
fprintf(output, "__attribute__((section(\"embed/%s\"))) const unsigned char %s[] = {\n", name_only, input_name);
}
else
{
fprintf(output, "__attribute__((section(\"embed/%s\"))) const unsigned char %s[] = {", name_only, input_name);
}
}
int c = 0;
int i = 0;
if (args->autowrap)
{
while ((c = fgetc(input)) != EOF)
{
if (i == 0)
{
fprintf(output, " ");
}
fprintf(output, "0x%02X", c);
fprintf(output, ", ");
if (i < 15)
{
fprintf(output, ", ");
}
else
{
fprintf(output, ",\n");
i = -1;
}
i++;
}
if (i > 0)
{
fprintf(output, "\n");
}
fprintf(output, " 0x00,\n");
fprintf(output, "};\n");
}
else
{
while ((c = fgetc(input)) != EOF)
{
fprintf(output, "0x%02X", c);
fprintf(output, ", ");
}
fprintf(output, "0x00");
fprintf(output, "};\n\n");
}
if (args->format[0] == 'h')
{
fprintf(output, "#endif /* %s_H */\n", input_name);
}
fclose(input);
fclose(output);
if (!args->quiet)
printf("Generated resource '%s'\n", input_name);
return EXIT_SUCCESS;
}