commit 81df5940827fa4347d112d3f81c926ef3a6acb80 Author: Timerix22 Date: Mon May 22 03:04:12 2023 +0600 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df4573d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +resource_embedder +*.o +*.exe diff --git a/README.md b/README.md new file mode 100644 index 0000000..cc811da --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Resource Embedder +Program that transforms files to array definitions in C. + +## building +```shell +./build.sh +``` + +## usage +```shell +./resource_embedder -o src/embedded_resources.h -d res -i res/file1 -i res/file2 -i res/file3 +``` +This command generates array definitions of files from `res/` in `src/embedded_resources.h`. EmbeddedFile.path properties wouldn't contain directory `res/`. + +Complete list of command line options could be shown using `-h flag` diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..6f40e52 --- /dev/null +++ b/build.sh @@ -0,0 +1,7 @@ +#/bin/sh +set -e +echo 'compiling resource_embedder...' +set -x +cc -Wall -Wextra -O2 resource_embedder.c -o resource_embedder +set +x +echo 'done' diff --git a/resource_embedder.c b/resource_embedder.c new file mode 100644 index 0000000..eb1d6e0 --- /dev/null +++ b/resource_embedder.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include + +// the program writes generated text to stdout +// other messages must be sent to stderr +#define printf USE_FPRINTF!!! + +#define exit_with_error(FORMAT, ARGS...) ({ \ + fprintf(stderr, "\e[91m\nerror: "FORMAT"\n", ## ARGS); \ + exit(4); \ +}) + +#define argis(STR) streq(arg, STR) || \ + streq(arg, "-"STR) || \ + streq(arg, "--"STR) + +//////////////////////////////////////////////// +// STR FUNCTIONS // +//////////////////////////////////////////////// + +bool streq(const char* key0,const char* key1){ + if(!key0) return key1 ? false : true; + if(!key1) return false; + while(*key0&&*key1) + if(*key0++ != *key1++) + return false; + return true; +} + +char* basedir_exclude(const char* path, const char* basename){ + int len=strlen(path); + int base_len=strlen(basename); + int i=0; + if(len>0 && base_len>0){ + if(basename[base_len-1]=='/' || basename[base_len-1]=='\\') + base_len--; // remove trailing path separator + if(len>base_len){ + while(i spaces +char* mult_space(int count){ + char* _mult_space_buf=malloc(count+1); + _mult_space_buf[count]=0; + memset(_mult_space_buf, ' ', count); + return _mult_space_buf; +} + +void print_line(bool print_lines, bool start_new_line){ + if(!print_lines) + return; + fflush(stdout); + if(start_new_line) + fprintf(stderr, "\n"); + fprintf(stderr, "------------------------------------------------------------\n"); + fflush(stderr); +} + +//////////////////////////////////////////////// +// WRITE CODE // +//////////////////////////////////////////////// + +bool _first_file_processed=false; +unsigned int _input_files_n=0; + +void process_file(const char* input_file_path, + const char* embedded_file_path, + FILE* out_file, + const char* out_file_path) +{ + bool print_lines=streq(out_file_path, "this_file"); + + if(!_first_file_processed){ + print_line(print_lines, false); + + int onml=strlen(out_file_path); + if(onml>43) onml=0; + char* _sp1=mult_space(43-onml); + fprintf(out_file, + // "////////////////////////////////////////////////////////////\n" + // "// //\n" + // "//%s%s%s//\n" + // "// //\n" + "////////////////////////////////////////////////////////////\n" + "// This file has been generated by resource_embedder //\n" + "// src: https://github.com/Timerix22/resource_embedder //\n" + "////////////////////////////////////////////////////////////\n" + "// USAGE: //\n" + "// Put inside any .c file //\n" + "// #define EMBEDDED_RESOURCE_POSTFIX your_postfix //\n" + "// #include \"%s\"%s//\n" + "// //\n" + "// Then you can access embedded files through //\n" + "// EmbeddedResourceFile_table_your_postfix. You can put //\n" + "// table content into a hashtable or get it by index. //\n" + "////////////////////////////////////////////////////////////\n" + "\n", + // mult_space(28-onml/2), outname, mult_space(28-onml/2+onml%2), + out_file_path, _sp1); + free(_sp1); + fprintf(out_file, + "typedef unsigned char _byte;\n" + "\n" + "typedef struct {\n" + " char* path;\n" + " _byte* data;\n" + " unsigned long long size;\n" + "} EmbeddedResourceFile;\n" + "\n" + "#ifndef _EmbeddedResourceFile_table\n" + "#ifdef EMBEDDED_RESOURCE_POSTFIX\n" + " #define _EmbeddedResourceFile_table \\\n" + " EmbeddedResourceFile_table##EMBEDDED_RESOURCE_POSTFIX\n" + " #define _EmbeddedResourceFile_table_count \\\n" + " EmbeddedResourceFile_table##EMBEDDED_RESOURCE_POSTFIX##_count\n" + "#else\n" + " #define _EmbeddedResourceFile_table \\\n" + " EmbeddedResourceFile_table\n" + " #define _EmbeddedResourceFile_table_count \\\n" + " EmbeddedResourceFile_table_count\n" + "#endif\n" + "#endif\n" + "extern EmbeddedResourceFile _EmbeddedResourceFile_table[];\n" + "extern unsigned int _EmbeddedResourceFile_table_count;" + "\n" + "\n" + "EmbeddedResourceFile _EmbeddedResourceFile_table[]={\n"); + print_line(print_lines, false); + } + + fprintf(stderr, "reading file %s\n", input_file_path); + print_line(print_lines, false); + + + FILE* input_file=fopen(input_file_path, "rb"); + if(input_file==NULL) + exit_with_error("can't open file %s", input_file_path); + + if(_first_file_processed) + fprintf(out_file, ",\n"); + // writing input file code header + fprintf(out_file, + " {\n" + " .path=(char*)\"%s\",\n" + " .data=(_byte[]){", + embedded_file_path); + + // writing input file content + int byte=0; + unsigned long long size=0; + while( (byte=fgetc(input_file)) != EOF ){ + if(size!=0) + fprintf(out_file, ","); + if(size%16==0) + fprintf(out_file, "\n "); + fprintf(out_file, "0x%X", byte); + size+=1; + } + fprintf(out_file, + "\n },\n" + " .size=%llu\n" + " }", + size); + fflush(out_file); + + print_line(print_lines,true); + if(ferror(input_file)){ + perror("unexpected end of stream: "); + exit_with_error("input read error"); + } + fclose(input_file); + + fprintf(stderr, "read %llu bytes\n", size); + + _first_file_processed=true; + _input_files_n++; +} + + + +//////////////////////////////////////////////// +// MAIN // +//////////////////////////////////////////////// + +int main(const int argc, const char * const* argv){ + FILE* out_file=NULL; + const char* out_file_path=NULL; + const char* basedir=""; + + for(int i=1; i