#include #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){ // remove trailing path separator if(basename[base_len-1]=='/' || basename[base_len-1]=='\\') base_len--; 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 write_header(FILE* out_file, const char* out_file_path){ int onml=strlen(out_file_path); if(onml>47) onml=0; char* _sp1=mult_space(47-onml); fprintf(out_file, "////////////////////////////////////////////////////////////////\n" "// This file was generated by resource_embedder //\n" "// https://timerix.ddns.net:3322/Timerix/resource_embedder //\n" "////////////////////////////////////////////////////////////////\n" "// USAGE: //\n" "// Put it in a SOURCE file to define variables //\n" "// #define EMBEDDED_RESOURCE_DEFINITION //\n" "// #define EMBEDDED_RESOURCE_POSTFIX your_postfix //\n" "// #include \"%s\"%s//\n" "// //\n" "// Put it in a HEADER file to declare external variables //\n" "// #define EMBEDDED_RESOURCE_POSTFIX your_postfix //\n" "// #include \"%s\"%s//\n" "// //\n" "// Then you can access embedded files through //\n" "// EmbeddedResource_table_your_postfix. You can get table //\n" "// content by index and put it into a hashtable or a map. //\n" "////////////////////////////////////////////////////////////////\n" "\n", out_file_path, _sp1, out_file_path, _sp1); free(_sp1); fprintf(out_file, "#pragma once\n" "#if __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" "#include \n" "#include \n" "\n" "typedef struct {\n" " const char* path;\n" " const char* data;\n" " size_t size;\n" "} EmbeddedResource;\n" "\n" "#define RSCAT(A,B,C...) A##B##C" "\n" "#ifdef EMBEDDED_RESOURCE_POSTFIX\n" " #define _EmbeddedResource_table(P) \\\n" " RSCAT(EmbeddedResource_table_, P)\n" " #define _EmbeddedResource_table_count(P) \\\n" " RSCAT(EmbeddedResource_table_, P, _count)\n" "#else\n" " #define _EmbeddedResource_table(P) \\\n" " EmbeddedResource_table\n" " #define _EmbeddedResource_table_count(P) \\\n" " EmbeddedResource_table_count\n" "#endif\n" "extern const EmbeddedResource _EmbeddedResource_table(EMBEDDED_RESOURCE_POSTFIX)[];\n" "extern const int _EmbeddedResource_table_count(EMBEDDED_RESOURCE_POSTFIX);\n" "\n" "#ifdef EMBEDDED_RESOURCE_DEFINITION\n" "const EmbeddedResource _EmbeddedResource_table(EMBEDDED_RESOURCE_POSTFIX)[]={\n" ); } void write_footer(FILE* out_file){ fprintf(out_file, "\n};\n\n" "const int _EmbeddedResource_table_count(EMBEDDED_RESOURCE_POSTFIX)=%u;\n" "#endif // EMBEDDED_RESOURCE_DEFINITION\n" "\n" "#undef _EmbeddedResource_table\n" "#undef _EmbeddedResource_table_count\n" "#undef EMBEDDED_RESOURCE_POSTFIX\n" "#undef RSCAT\n" "\n" "#if __cplusplus\n" "}\n" "#endif\n", _input_files_n ); } 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, "stdout"); 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=\"%s\",\n" " .data=(const char[]){", embedded_file_path); // writing input file content int byte=0; long long unsigned int size=0; while( (byte=fgetc(input_file)) != EOF ){ if(size%16==0) fprintf(out_file, "\n "); fprintf(out_file, "0x%02X,", byte); size++; } // trailing zero to use file.data as cstring fprintf(out_file, "0x0"); 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=stdout; const char* out_file_path="stdout"; const char* basedir=""; for(int i=1; i= argc) exit_with_error("expected an argument after -o"); const char* file_path=argv[++i]; out_file_path=file_path; out_file=fopen(out_file_path, "wb"); if(out_file==NULL) exit_with_error("can't open file %s", out_file_path); fprintf(stderr, "output file has been set to %s\n", out_file_path); bool print_lines=streq(out_file_path, "stdout"); print_line(print_lines, false); write_header(out_file, out_file_path); print_line(print_lines, false); } else if(argis("d")){ if (i + 1 >= argc) exit_with_error("expected an argument after -d"); basedir=argv[++i]; fprintf(stderr, "basedir is set to: %s\n", basedir); } else if(argis("i")){ if (i + 1 >= argc) exit_with_error("expected an argument after -i"); const char* input_file_path=argv[++i]; char* embedded_path=basedir_exclude(input_file_path, basedir); fprintf(stderr, "input file path: %s\n", arg); fprintf(stderr, "embedded path: %s\n", embedded_path); process_file(input_file_path, embedded_path, out_file, out_file_path); free(embedded_path); } else exit_with_error("unknown argument: %s", arg); } if(out_file_path!=NULL){ bool out_file_set=!streq(out_file_path, "stdout"); if(!out_file_set) print_line(true, false); write_footer(out_file); if(!out_file_set) fclose(out_file); print_line(true, false); } return 0; }