2023-07-13 14:29:58 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
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. <https://fsf.org/>
|
|
|
|
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 <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#define VERSION "0.0.1"
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
typedef enum _format
|
|
|
|
{
|
|
|
|
FORMAT_C,
|
|
|
|
FORMAT_H,
|
|
|
|
} format_t;
|
|
|
|
|
|
|
|
typedef enum _type
|
|
|
|
{
|
|
|
|
TYPE_EMBED,
|
|
|
|
TYPE_ADVISORY,
|
|
|
|
} type_t;
|
|
|
|
|
2023-07-13 14:29:58 +00:00
|
|
|
typedef struct _embed
|
|
|
|
{
|
|
|
|
char *input;
|
|
|
|
char *output;
|
2023-10-21 17:48:18 +00:00
|
|
|
format_t format;
|
|
|
|
type_t type;
|
2023-07-13 14:29:58 +00:00
|
|
|
int verbose;
|
|
|
|
int quiet;
|
2023-10-19 12:02:01 +00:00
|
|
|
int autowrap;
|
2023-07-13 14:29:58 +00:00
|
|
|
} 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};
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
while ((c = getopt(argc, argv, "hvi:o:f:t:Vqw")) != -1)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
|
|
|
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':
|
2023-10-21 17:48:18 +00:00
|
|
|
args.format = FORMAT_C;
|
2023-07-13 14:29:58 +00:00
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
args.format = FORMAT_H;
|
2023-07-13 14:29:58 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2023-10-21 17:48:18 +00:00
|
|
|
case 't':
|
|
|
|
// check -t=embed -t=advisory handle equal sign and skip it
|
|
|
|
if (optarg[0] == '=')
|
|
|
|
{
|
|
|
|
optarg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (optarg[0])
|
|
|
|
{
|
|
|
|
case 'e':
|
|
|
|
args.type = TYPE_EMBED;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
args.type = TYPE_ADVISORY;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Unknown type: %s defaulting to embed\n", optarg);
|
|
|
|
args.type = TYPE_EMBED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2023-07-13 14:29:58 +00:00
|
|
|
case 'V':
|
|
|
|
args.verbose = 1;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
args.quiet = 1;
|
|
|
|
break;
|
2023-10-19 12:02:01 +00:00
|
|
|
case 'w':
|
|
|
|
args.autowrap = 1;
|
|
|
|
break;
|
2023-07-13 14:29:58 +00:00
|
|
|
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");
|
2023-10-21 17:48:18 +00:00
|
|
|
printf(" -t, --type=TYPE Output type (embed, advisory)\n");
|
|
|
|
printf(" -w, --autowrap Autowrap output\n");
|
2023-07-13 14:29:58 +00:00
|
|
|
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 <space> 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;
|
|
|
|
}
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
char *formats[] = {"c", "h"};
|
2023-07-13 14:29:58 +00:00
|
|
|
|
|
|
|
if (args->verbose)
|
|
|
|
{
|
|
|
|
printf("Input file: %s\n", args->input);
|
|
|
|
printf("Output file: %s\n", args->output);
|
2023-10-21 17:48:18 +00:00
|
|
|
printf("Output format: %s\n", formats[args->format]);
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
FILE *output = NULL;
|
2023-07-13 14:29:58 +00:00
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
if (args->output != NULL)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-19 12:02:01 +00:00
|
|
|
output = fopen(args->output, "w");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output = stdout;
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
char *typ;
|
|
|
|
|
|
|
|
switch (args->type)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-21 17:48:18 +00:00
|
|
|
case TYPE_EMBED:
|
|
|
|
typ = "embed";
|
|
|
|
break;
|
|
|
|
case TYPE_ADVISORY:
|
|
|
|
typ = "advisory";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
typ = "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->format == FORMAT_C)
|
|
|
|
{
|
|
|
|
fprintf(output, "__attribute__((section(\"%s/%s\"))) const unsigned char %s[] = {", typ, name_only, input_name);
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
if (args->autowrap)
|
|
|
|
{
|
2023-10-21 17:48:18 +00:00
|
|
|
fprintf(output, "\n");
|
2023-10-19 12:02:01 +00:00
|
|
|
}
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
2023-10-21 17:48:18 +00:00
|
|
|
else if (args->format == FORMAT_H)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
|
|
|
fprintf(output, "#pragma once\n");
|
|
|
|
fprintf(output, "#ifndef %s_H\n", input_name);
|
2023-10-21 17:48:18 +00:00
|
|
|
fprintf(output, "__attribute__((section(\"%s/%s\"))) const unsigned char %s[] = {", typ, name_only, input_name);
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
if (args->autowrap)
|
|
|
|
{
|
2023-10-21 17:48:18 +00:00
|
|
|
fprintf(output, "\n");
|
2023-10-19 12:02:01 +00:00
|
|
|
}
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int c = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
if (args->autowrap)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-19 12:02:01 +00:00
|
|
|
while ((c = fgetc(input)) != EOF)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-19 12:02:01 +00:00
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
fprintf(output, " ");
|
|
|
|
}
|
2023-07-13 14:29:58 +00:00
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
fprintf(output, "0x%02X", c);
|
2023-07-13 14:29:58 +00:00
|
|
|
|
|
|
|
fprintf(output, ", ");
|
2023-10-19 12:02:01 +00:00
|
|
|
if (i < 15)
|
|
|
|
{
|
|
|
|
fprintf(output, ", ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(output, ",\n");
|
|
|
|
i = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
2023-10-19 12:02:01 +00:00
|
|
|
|
|
|
|
if (i > 0)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-19 12:02:01 +00:00
|
|
|
fprintf(output, "\n");
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
if (args->type == TYPE_EMBED)
|
|
|
|
fprintf(output, " 0x00,\n");
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
fprintf(output, "};\n");
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
2023-10-19 12:02:01 +00:00
|
|
|
else
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
2023-10-19 12:02:01 +00:00
|
|
|
while ((c = fgetc(input)) != EOF)
|
|
|
|
{
|
|
|
|
fprintf(output, "0x%02X", c);
|
|
|
|
fprintf(output, ", ");
|
|
|
|
}
|
2023-10-21 17:48:18 +00:00
|
|
|
|
|
|
|
if (args->type == TYPE_EMBED)
|
|
|
|
fprintf(output, "0x00");
|
|
|
|
|
2023-10-19 12:02:01 +00:00
|
|
|
fprintf(output, "};\n\n");
|
2023-07-13 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2023-10-21 17:48:18 +00:00
|
|
|
if (args->format == FORMAT_H)
|
2023-07-13 14:29:58 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|