mirror of
https://github.com/ganelson/inform.git
synced 2024-07-16 22:14:23 +03:00
186 lines
7.4 KiB
Plaintext
186 lines
7.4 KiB
Plaintext
blorblib.c: A more or less portable C library for Z-machine interpreters
|
|
which want to use Blorb files.
|
|
|
|
Version 1.0.2
|
|
Andrew Plotkin <erkyrath@eblong.com>
|
|
http://www.eblong.com/zarf/blorb/index.html
|
|
|
|
I'll try to keep this simple. See blorb.h for detailed type definitions.
|
|
|
|
General notes: Most of these functions return an error code (type
|
|
bb_err_t, which is equivalent to int.) Always check this error code. If
|
|
it's non-zero, the call failed and no other information was returned.
|
|
|
|
What you do is, compile blorblib.c into your interpreter, and #include
|
|
"blorb.h". Be sure to uncomment one of the ENDIAN definitions in
|
|
"blorb.h". (If you get it wrong, the library will tell you when you try
|
|
to use it.)
|
|
|
|
When the your interpreter starts up and is given a Blorb file, you
|
|
should open the file. Then call:
|
|
|
|
bb_err_t err;
|
|
FILE *file; /* The Blorb file you just opened */
|
|
bb_map_t *map;
|
|
err = bb_create_map(file, &map);
|
|
|
|
If err is zero (bb_err_None), then map now points to an (opaque)
|
|
structure which describes the Blorb file. You will use this value in all
|
|
future blorblib calls.
|
|
|
|
(It's ok to have more than one Blorb file open at a time; you get
|
|
different bb_map_t pointers.)
|
|
|
|
When you are finished with the Blorb file, call
|
|
|
|
err = bb_destroy_map(map);
|
|
|
|
to destroy the map structure and all its data (including data chunks it
|
|
has loaded.) After bb_destroy_map() returns, you can fclose(file). Do
|
|
*not* close the file while the map structure still exists. blorblib
|
|
relies on the open file to load resources.
|
|
|
|
There are three vaguely-defined layers in this API. I'm not going to go
|
|
to the trouble of insulating you from the lower layers -- you can't get
|
|
*too* confused -- but it's generally easier to use the higher-level
|
|
calls rather than the lower level.
|
|
|
|
All three layers use a similar protocol to load in data. You call a load
|
|
function, and pass in a method constant, and a pointer to a bb_result_t
|
|
structure. The library fills in the bb_result_t structure according to
|
|
the load method you requested.
|
|
|
|
#define bb_method_DontLoad (0)
|
|
#define bb_method_Memory (1)
|
|
#define bb_method_FilePos (2)
|
|
|
|
typedef struct bb_result_struct {
|
|
int chunknum;
|
|
union {
|
|
void *ptr;
|
|
uint32 startpos;
|
|
} data;
|
|
uint32 length;
|
|
} bb_result_t;
|
|
|
|
If you request bb_method_Memory, then result.data.ptr will contain a
|
|
pointer to the data you requested; result.length is the number of bytes.
|
|
The library allocates this memory, so you should not write into it or
|
|
try to free() it. The library is sensible about remembering what data is
|
|
loaded; if you load the same chunk twice, it will not allocate two
|
|
identical pieces of memory. To deallocate the memory, call
|
|
bb_unload_chunk(result.chunknum).
|
|
|
|
If you request bb_method_FilePos, then result.data.startpos will contain
|
|
the position in the Blorb file of the data; result.length is the number
|
|
of bytes. You can use fseek() and the usual stdio functions to read the
|
|
data yourself.
|
|
|
|
If you request bb_method_DontLoad, then result.data won't contain any
|
|
meaningful data. However, result.length and result.chunknum will still
|
|
be set.
|
|
|
|
* The bottom layer (chunk loading): These are calls you can use to load
|
|
an IFF chunk directly.
|
|
|
|
bb_err_t bb_load_chunk_by_type(bb_map_t *map, int method,
|
|
bb_result_t *res, uint32 chunktype, int count);
|
|
|
|
This loads a chunk by its IFF chunk type. If count is zero, it loads the
|
|
first chunk of that type; if 1, the second; and so on. You probably
|
|
shouldn't do this to get resource chunks (sounds, images, executable
|
|
data). However, it's the only way to load the optional chunks -- author,
|
|
copyright, and annotation.
|
|
|
|
bb_err_t bb_load_chunk_by_number(bb_map_t *map, int method,
|
|
bb_result_t *res, int chunknum);
|
|
|
|
This loads a chunk based on its chunknum. (Note that a chunk number is
|
|
*not* the same as a resource number.) You might do this using a chunknum
|
|
that you got from the result structure after a previous load.
|
|
|
|
bb_err_t bb_unload_chunk(bb_map_t *map, int chunknum);
|
|
|
|
This deallocates the memory allocated by a bb_method_Memory load. You
|
|
would use the chunknum that you got from the result structure after the
|
|
load. If no memory is allocated, this does nothing.
|
|
|
|
* The middle layer (resource loading): These are calls you use to load a
|
|
resource based on usage.
|
|
|
|
bb_err_t bb_load_resource(bb_map_t *map, int method, bb_result_t
|
|
*res, uint32 usage, int resnum);
|
|
|
|
This loads a chunk based on usage (bb_ID_Snd, bb_ID_Pict, or bb_ID_Exec)
|
|
and resource number. Note that a resource number is *not* the same as a
|
|
chunk number. The resource number is a constant, which the game file
|
|
uses to find the data. The chunk number is just an internal key in the
|
|
IFF file.
|
|
|
|
bb_err_t bb_count_resources(bb_map_t *map, uint32 usage, int *num,
|
|
int *min, int *max);
|
|
|
|
This counts how many resources there are for a particular usage, and
|
|
their minimum and maximum resource numbers. The results are written into
|
|
*num, *min, and *max. (Any of these pointers can be NULL if you don't
|
|
care about that value.) If there are no resources of that usage, all
|
|
three values will be zero.
|
|
|
|
* The top layer (resource loading with extra data): These are special
|
|
calls for loading sound or image resources, which also return extra
|
|
information (looping flag for sounds, resolution data for images.)
|
|
|
|
bb_err_t bb_load_resource_pict(bb_map_t *map, int method,
|
|
bb_result_t *res, int resnum, bb_aux_pict_t **auxdata);
|
|
|
|
bb_err_t bb_load_resource_snd(bb_map_t *map, int method, bb_result_t
|
|
*res, int resnum, bb_aux_sound_t **auxdata);
|
|
|
|
These do what they say they do. If you don't care about the extra data,
|
|
pass NULL as the last argument; the result is effectively the same as
|
|
bb_load_resource(). If you do care, you should declare pointers
|
|
bb_aux_pict_t *auxpic;
|
|
bb_aux_sound_t *auxsound;
|
|
and pass &auxpict or &auxsound as the last argument. The pointer may be
|
|
set to NULL (meaning no extra data for this resource), or it may be set
|
|
pointing to a structure you can read. (This structure is allocated by
|
|
the library, so you should not write into or free() it.)
|
|
|
|
* There are also some calls for loading data which is not associated
|
|
with any particular resource. You could get this data yourself with
|
|
bb_load_chunk_by_type(), but these calls are easier.
|
|
|
|
uint16 bb_get_release_num(bb_map_t *map);
|
|
|
|
The release number of the resource file. If there is none, this returns
|
|
0.
|
|
|
|
bb_zheader_t *bb_get_zheader(bb_map_t *map);
|
|
|
|
The Z-code header data (which gives the serial number, release number,
|
|
and checksum of the Z-code file this Blorb file is associated with.) If
|
|
there is none, this returns NULL.
|
|
|
|
bb_resolution_t *bb_get_resolution(bb_map_t *map);
|
|
|
|
The resolution data (which gives the preferred, minimum, and maximum
|
|
window size.) If there is none, this returns NULL.
|
|
|
|
bb_err_t bb_get_palette(bb_map_t *map, bb_palette_t **res);
|
|
|
|
The palette data. You should declare a pointer
|
|
bb_palette_t *pal;
|
|
and pass &pal as the second argument. If pal is set to NULL, there is no
|
|
palette data. If not, you should test pal->isdirect. If pal->isdirect is
|
|
TRUE, then pal->data.depth contains a preferred color depth (either 16
|
|
ot 32 bits per pixel.) If pal->isdirect is FALSE, then pal->data.table
|
|
contains a list of up to 256 preferred color entries;
|
|
pal->data.table.colors is an array of entries, and
|
|
pal->data.table.numcolors is the length of the array.
|
|
|
|
(If you're wondering why bb_get_palette() doesn't just return a pointer
|
|
like bb_get_zheader() and bb_get_resolution(), it's because the palette
|
|
isn't loaded until you ask for it. So there might be read or allocation
|
|
errors. Ok, it's not a good reason.)
|
|
|