Hi All,
I’m designing a resource file format to hold game data (scripts, images,
musics, sound effects etc.) and would like some input from the community.
First, why another resource file? Because I want two things other
resource files don’t offer (at least that I’m aware of):
A. Fast access through mmap (the file can be mmapped to the process
address space and used with very little setup)
B. Spare space where I could insert the digital signature of the file.
This space must be filled with zeroes while computing the hash for the
signature.
The preliminary version is working quite well. Data is accessed by name
(char *), with a reader that supports basic data input operations being
returned. Since the file is mmaped, the location of a given chunk of
data within the file is quickly found via a bsearch call. Data can be
stored without compression (good for mp3, ogg, jpeg…) or bzipped. The
resource file can even be part of another file, the most common use
being to append the resource file to an executable.
There is also support for transparently using a directory instead of a
real resource file just like zziplib, and reading entries via SDL_RWops.
So my questions are:
- Is there any thing bad about mmapping a resource file? The file size
can easily be greater than 4 GiB. - Are there other resource file formats that provide A and B above?
- Are there other important characteristics for a resource file format
I’m missing? - Do you have requirements for a new resource file?
The exposed interface so far is:
--------------------8<--------------------
/* Seek modes. */
#define AF_SEEK_SET 0
#define AF_SEEK_CUR 1
#define AF_SEEK_END 2
/* The opaque file type. */
struct af_file_t;
typedef struct af_file_t af_file_t;
/* The opaque reader type. */
struct af_reader_t;
typedef struct af_reader_t af_reader_t;
/* The callback type used to return the address of needed functions,
i.e. BZ2_bzDecompress and friends. This allow the application
to statically link support libraries as bzip2 or dinamically load them
from anywhere in the file system. */
typedef void *(*af_dynamic_link_t)(const char *library_name, const char
*function_name);
/* Information filled by af_entry_get_info and af_iterate. */
typedef struct {
const char *name;
uint8_t compression[4];
uint32_t compressed_size;
uint32_t uncompressed_size;
const void *data;
} af_entry_info_t;
/* Sets the callback for the load of support libraries. */
void af_set_dynamic_link_callback(af_dynamic_link_t call_back);
/* Opens the resource file, possibly with an offset from the
beginning of the named file. Size defaults to the number
of bytes left in the file starting at offset, but can be specified
if the resource file is embedded in the middle of some
other file. */
af_file_t *af_open(const char *name, uint32_t offset, uint32_t size);
/* Closes the resource file, freeing all allocated resources. */
void af_close(af_file_t *file);
/* Calls the process callback for all entries in the resource file. */
int af_iterate(af_file_t *file, int (*process)(af_entry_info_t *info,
void *udata), void *udata);
/* Opens an entry for reading. */
af_reader_t *af_entry_open(af_file_t *file, const char *name);
/* Reads size bytes into buffer. */
int af_entry_read(af_reader_t *reader, void *buffer, int size);
/* Changes the location of the next read operation. */
int af_entry_seek(af_reader_t *reader, int offset, int whence);
/* Closes the reader, freeing all allocated resources. */
int af_entry_close(af_reader_t *reader);
/* Returns the current position within the entry. */
int af_entry_tell(af_reader_t *reader);
/* Returns information of the entry associated with the reader. */
int af_entry_get_info(af_file_t *file, af_entry_info_t *info, const char
*name);
--------------------8<--------------------
Cheers,
Andre