Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to embed a file into an executable file?

I have two problems, the first has been solved.

Current problem
If I embed a file that requires a library to load it, such as a jpeg image or a mp3 music, I will need to use the file as input to the library. However, each library is different and uses a way to get a file as input, the input may be the file name or a FILE* pointer (from libc's file interface).

I would like to know how to access an embedded file with a name. It will be inefficient if I create a temporary file, is there another way? Can I map a file name to memory? My platforms are Windows and Linux.

If show_file(const char* name) is a function from a library, I will need a string to open the file.
I have seen these questions:
How to get file descriptor of buffer in memory?
Getting Filename from file descriptor in C

and the following code is my solution. Is it a good solution? Is it inefficient?

# include <stdio.h>
# include <unistd.h>

extern char _binary_data_txt_start;
extern const void* _binary_data_txt_size;
const size_t len = (size_t)&_binary_data_txt_size;

void show_file(const char* name){
    FILE* file = fopen(name, "r");
    if (file == NULL){
        printf("Error (show_file): %s\n", name);
        return;
    }

    while (true){
        char ch = fgetc(file);
        if (feof(file) )
            break;
        putchar( ch );
    }
    printf("\n");

    fclose(file);
}

int main(){

    int fpipe[2];
    pipe(fpipe);

    if( !fork() ){
        for( int buffsize = len, done = 0; buffsize>done; ){
            done += write( fpipe[1], &_binary_data_txt_start + done, buffsize-done );
        }
        _exit(0);
    }

    close(fpipe[1]);
    char name[200];
    sprintf(name, "/proc/self/fd/%d", fpipe[0] );

    show_file(name);

    close(fpipe[0]);
}

The other problem (solved)
I tried to embed a file on Linux, with GCC, and it worked. However, I tried to do the same thing on Windows, with Mingw, and it did not compile.

The code is:

# include <stdio.h>

extern char _binary_data_txt_start;
extern char _binary_data_txt_end;

int main(){
    for (char* my_file = &_binary_data_txt_start; my_file <= &_binary_data_txt_end; my_file++)
        putchar(*my_file);
    printf("\n");
}

The compilation commands are:

objcopy --input-target binary --output-target elf32-i386 --binary-architecture i386 data.txt data.o
g++ main.cpp data.o -o test.exe

On Windows, I get the following compiler error:

undefined reference to `_binary_data_txt_start'
undefined reference to `_binary_data_txt_end'

I tried to replace elf32-i386 with i386-pc-mingw32, but I still get the same error.

like image 962
Squall Avatar asked Jul 22 '11 03:07

Squall


2 Answers

I think that for this to work with MinGW you'll need to remove the leading underscore from the names in the .c file. See Embedding binary blobs using gcc mingw for some details.

See if using the following helps:

extern char binary_data_txt_start;
extern char binary_data_txt_end;

If you need the same source to work for Linux or MinGW builds, you might need to use the preprocessor to have the right name used in the different environments.

like image 166
Michael Burr Avatar answered Oct 02 '22 03:10

Michael Burr


If you're using a library that requires a FILE* for reading data, then you can use fmemopen(3) to create a pseudofile out of a memory blob. This will avoid creating a temporary file on disk. Unfortunately, it's a GNU extension, so I don't know if it's available with MinGW (likely not).

However, most well-written libraries (such as libpng and the IJG's JPEG library) provide routines for opening a file from memory as opposed to from disk. libpng, in particular, even offers a streaming interface, where you can incrementally decode a PNG file before it's been completely read into memory. This is useful if, say, you're streaming an interlaced PNG from the network and you want to display the interlaced data as it loads for a better user experience.

like image 24
Adam Rosenfield Avatar answered Oct 02 '22 03:10

Adam Rosenfield