Indice

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 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] <input_file> <output_file>

          -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 <stdio.h>
#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 <stdio.h>
#ifdef _WIN32 
	#include <windows.h>
#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)

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] <input_file> <output_file>
//
//          -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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#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] <input_file> <output_file>\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