====== Includere risorse binarie in sorgenti C ====== Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//18/12/2010//** \\ \\ E' possibile includere dentro il nostro sorgente C e quindi dopo la compilazione anche dentro il nostro eseguibile file binari come immagini, filmati o qualsiasi altro file. Puo' essere utile per trasportare risorse dei nostri programmi, oppure anche per preparare eseguibili che modificano alcuni file sostituendoli. Insomma gli scopi potrebbero essere innumerevoli. \\ I file da includere devono per prima cosa essere trasformati in un array di interi in forma esadecimale (per comodita') e per fare questo ci possiamo avvalere dell'utility [[http://wiki.wxwidgets.org/Embedding_PNG_Images-Bin2c_In_C|bin2c]] di Sandro Sigala (riporto il codice di bin2c in fondo alla pagina per sicurezza). ===== Prepariamo il file binario ===== Nel nostro caso includero' un'immagine e quindi ho bisogno di lanciare bin2c sull'immagine in modo tale da crearmi il file include con dentro array di interi in forma esadecimale. bin2c -c logo.png myfile.c di seguito l'utilizzo di bin2c: \\ syntax: bin2c [-c] [-z] -c add the "const" keyword to definition -z terminate the array with a zero (useful for embedded C strings) examples: bin2c -c myimage.png myimage_png.cpp bin2c -z sometext.txt sometext_txt.cpp quindi otterremo un file del genere: static const unsigned char MyArrayFile[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x7a, 0x08, 0x02, 0x00, 0x00, 0x00, 0x83, 0x71, 0x0e, 0x2f, 0x00, 0x00, 0x00, ...(molto grande)... 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd7, 0x07, 0x0c, }; quindi a noi non resta altro che riscrivere questo enorme array in forma binaria su di un file. ==== Alternativa a bin2c ==== Possiamo generare il nostro array anche con uno scrip bash: (echo "const unsigned char binary_data[] = {"; od -txC -v filebinario.jpg | sed -e "s/^[0-9]*//" -e s"/ \([0-9a-f][0-9a-f]\)/0x\1,/g" -e"\$d" | sed -e"\$s/,$/};/") >array-file-binario.c ===== Codice della nostra applicazione ===== **main.c** #include #include "myfile.c" //contiene l'array esadecimale del nostro file int main(int argc, char* argv[]) { /*Creo il file loghetto.png con il contenuto(binario) dell'array MyArrayFile (vedi myfile.c) */ FILE* DataFile = fopen ("loghetto.png", "w"); fwrite ( MyArrayFile , sizeof(unsigned char) , sizeof(MyArrayFile) , DataFile ); fclose(DataFile); return 0; } **Compilazione** gcc -o main main.c Avviando l'eseguibile creera' un file contenente la nostra immagine, se il file gia' esiste lo sovrascrive. ===== Codice per la versione multipiattaforma Windows/Linux ===== #include #ifdef _WIN32 #include #endif #include "candy.c" //contiene l'array esadecimale del nostro file int main(int argc, char* argv[]) { #ifdef __linux__ /*Creo il file loghetto.png con il contenuto(binario) dell'array MyArrayFile (vedi myfile.c) */ FILE* DataFile = fopen ("loghetto.jpg", "w"); fwrite ( candy_jpg , sizeof(unsigned char) , sizeof(candy_jpg) , DataFile ); fclose(DataFile); #endif #ifdef _WIN32 /*Creo il file loghetto.png con il contenuto(binario) dell'array MyArrayFile (vedi myfile.c) */ FILE* DataFile = CreateFile ( "loghetto.jpg", FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); int n; WriteFile ( DataFile, candy_jpg, sizeof candy_jpg, &n, NULL ); fclose(DataFile); #endif return 0; } **crosscompilazione (da linux per windows)** i586-mingw32msvc-gcc main.c -o main.exe ===== Sorgente bin2c ===== Di Sandro Sigala ([[http://wiki.wxwidgets.org/Embedding_PNG_Images-Bin2c_In_C|http://wiki.wxwidgets.org/Embedding_PNG_Images-Bin2c_In_C]]) **bin2c.c** // bin2c.c // // convert a binary file into a C source vector // // THE "BEER-WARE LICENSE" (Revision 3.1415): // sandro AT sigala DOT it wrote this file. As long as you retain this notice you can do // whatever you want with this stuff. If we meet some day, and you think this stuff is // worth it, you can buy me a beer in return. Sandro Sigala // // syntax: bin2c [-c] [-z] // // -c add the "const" keyword to definition // -z terminate the array with a zero (useful for embedded C strings) // // examples: // bin2c -c myimage.png myimage_png.cpp // bin2c -z sometext.txt sometext_txt.cpp #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 1024 #endif int useconst = 0; int zeroterminated = 0; int myfgetc(FILE *f) { int c = fgetc(f); if (c == EOF && zeroterminated) { zeroterminated = 0; return 0; } return c; } void process(const char *ifname, const char *ofname) { FILE *ifile, *ofile; ifile = fopen(ifname, "rb"); if (ifile == NULL) { fprintf(stderr, "cannot open %s for reading\n", ifname); exit(1); } ofile = fopen(ofname, "wb"); if (ofile == NULL) { fprintf(stderr, "cannot open %s for writing\n", ofname); exit(1); } char buf[PATH_MAX], *p; const char *cp; if ((cp = strrchr(ifname, '/')) != NULL) { ++cp; } else { if ((cp = strrchr(ifname, '\\')) != NULL) ++cp; else cp = ifname; } strcpy(buf, cp); for (p = buf; *p != '\0'; ++p) { if (!isalnum(*p)) *p = '_'; } fprintf(ofile, "static %sunsigned char %s[] = {\n", useconst ? "const " : "", buf); int c, col = 1; while ((c = myfgetc(ifile)) != EOF) { if (col >= 78 - 6) { fputc('\n', ofile); col = 1; } fprintf(ofile, "0x%.2x, ", c); col += 6; } fprintf(ofile, "\n};\n"); fclose(ifile); fclose(ofile); } void usage(void) { fprintf(stderr, "usage: bin2c [-cz] \n"); exit(1); } int main(int argc, char **argv) { while (argc > 3) { if (!strcmp(argv[1], "-c")) { useconst = 1; --argc; ++argv; } else if (!strcmp(argv[1], "-z")) { zeroterminated = 1; --argc; ++argv; } else { usage(); } } if (argc != 3) { usage(); } process(argv[1], argv[2]); return 0; } **Compilazione** gcc -o bin2c bin2c.c