I read this question in the archive a little while ago, and I remember
a funny hack from, uh, a very long time ago, that is actually more
portable than putting your resource file at the end of your executable
(which requires knowing the format of the header for your executable
format), but I didn’t have posting access at the time (was too lazy to
subscribe just for that!). Now I do, so there you go…
First, you need to make an object file from your resource file. This
is the least portable way, but it seems that every platform in the
universe has a way of doing that, going all the way back to CP/M, DOS
and Apple DOS. On Linux, binutils makes it pretty easy, with the
following command-line:
objcopy -I binary -O elf32-i386 -B i386 --rename-section
.data=.rodata,alloc,load,readonly,data,contents README.txt readme.o
The “-I binary” tells it that the source is binary. binutils will make
a set of three symbols, called _binary_README_txt_start,
_binary_README_txt_end and _binary_README_txt_size. The last one is
special, because it is a symbol with a fake address that can be used
to add to the start one (if you actually read it, it will probably
cause a segfault).
The “-O elf32-i386” specifies the format. Weirdly enough, you have to
also specify the architecture with “-B i386”. If you use “file” on an
object file, the first is the beginning part (“ELF 32-bit LSB”), and
the -B is the second part (“Intel 80386”).
The "–rename-section .data=.rodata,alloc,load,readonly,data,contents"
part is optional. It put the data in the read-only text segment,
instead of the writable data segment (the default). This both protects
you from writing to it accidentally (it will segfault), but also makes
it possible for the operating system to share that data between
multiple instances of the same process, using less physical memory).
In both cases, modern operating systems demand-paging will make it
that there is only physical memory consumed for pages that were used
recently (you could put a gigabyte file in there, and it will (more or
less) happily run on a system with 128 megs of memory).
To use it, you do as follow:
#include <stdio.h>
extern char _binary_README_txt_start[];
extern char _binary_README_txt_end[];
/* The following is not really needed, it’s there just for the demo. */
extern char _binary_README_txt_size[];
int main() {
printf(“start: %p\n end: %p\n size: %p\n”, _binary_README_txt_start,
_binary_README_txt_end, _binary_README_txt_size);
fwrite(_binary_README_txt_start, _binary_README_txt_end -
_binary_README_txt_start, 1,
stdout);
return 0;
}
In actual use, you can wrap this in a number of ways to make it more
portable. If you have a function that returns a pointer to the data,
for example, you could have it mmap() the file if it is external,
return &_binary_README_txt_start, or load it with stdio (or something)
and return a pointer to malloc()'d memory (you’ll need a "release"
function too, to munmap() or free() the memory, of course, which would
be in a no-op when using this trick).
If you’re clever, you can have resources in formats that are
pre-converted as much as possible. If your game is fixed resolution,
pre-compiled run-length encoding and such things might be possible. If
you’re bordering on the insane (which might apply when coding for some
consoles and hand-helds), you could even have SDL_Surface structures
and such baked right in there! Make a “resource creating program” that
loads the images the normal way, stuffs them in SDL surfaces, then
serialize them into your resource file (unportable, but okay, because
it will be baked into your executable, which isn’t portable either in
many cases). You’ll want to do some pointer swizzling (look it up on
Wikipedia), then you’re good to go!
I can’t really guarantee that your sanity will survive using those
tricks, though.
Have fun!–
http://pphaneuf.livejournal.com/