From feb291df7604befe1d8ed75fd1ef4faae8a30d80 Mon Sep 17 00:00:00 2001 From: David Griffith Date: Thu, 16 Aug 2012 02:08:47 -0700 Subject: [PATCH] Now using DOS-specific Blorb code. Now Blorb works in DOS! --- Makefile.tc | 11 +- src/dos/bcblorb.c | 835 +++++++++++++++++++++++++++++++++++++++++++++ src/dos/bcinit.c | 2 +- src/dos/blorb.h | 152 +++++++++ src/dos/blorblow.h | 72 ++++ 5 files changed, 1064 insertions(+), 8 deletions(-) create mode 100644 src/dos/bcblorb.c create mode 100644 src/dos/blorb.h create mode 100644 src/dos/blorblow.h diff --git a/Makefile.tc b/Makefile.tc index 957a581..e385629 100644 --- a/Makefile.tc +++ b/Makefile.tc @@ -26,7 +26,8 @@ DOS_OBJECTS = $(DOS_DIR)\bcinit.o \ $(DOS_DIR)\bcpic.o \ $(DOS_DIR)\bcsample.o \ $(DOS_DIR)\bcscreen.o \ - $(DOS_DIR)\bctext.o + $(DOS_DIR)\bctext.o \ + $(DOS_DIR)\bcblorb.o \ CORE_DIR = src\common CORE_OBJECTS = $(CORE_DIR)\buffer.o \ @@ -50,24 +51,20 @@ CORE_OBJECTS = $(CORE_DIR)\buffer.o \ $(CORE_DIR)\quetzal.o \ $(CORE_DIR)\err.o -BLORB_DIR = src\blorb -BLORB_OBJECTS = $(BLORB_DIR)\blorblib.o - .SUFFIXES: .c .o .h .c.o: - $(CC) $(CFLAGS) $(DEFS) -I$(DOS_DIR) -I$(CORE_DIR) -I$(BLORB_DIR) -c -o$@ $< + $(CC) $(CFLAGS) $(DEFS) -I$(DOS_DIR) -I$(CORE_DIR) -c -o$@ $< $(TLIB) $(LIBRARY) +-$@ all: frotz clean: - $(RM) $(BLORB_DIR)\*.o $(RM) $(CORE_DIR)\*.o $(RM) $(DOS_DIR)\*.o $(RM) *.lib $(RM) *.exe $(RM) *.bak -frotz: $(BLORB_OBJECTS) $(DOS_OBJECTS) $(CORE_OBJECTS) +frotz: $(DOS_OBJECTS) $(CORE_OBJECTS) $(CC) $(CFLAGS) -e$(BINNAME) $(LIBRARY) diff --git a/src/dos/bcblorb.c b/src/dos/bcblorb.c new file mode 100644 index 0000000..0d0578b --- /dev/null +++ b/src/dos/bcblorb.c @@ -0,0 +1,835 @@ +/* blorblib.c: Blorb file reader library, version 1.0.2. + Designed by Andrew Plotkin + http://www.eblong.com/zarf/blorb/index.html + + This is portable code to read a Blorb file. Add it to your + interpreter, #include "blorb.h", and you're ready to go. +*/ + +#include +#include +#include "blorb.h" +#include "blorblow.h" + +/* This endian stuff needs to be fixed with something from + * http://www.ibm.com/developerworks/aix/library/au-endianc/index.html + */ + +#ifdef BLORB_BIG_ENDIAN +static char contentsticker[] = "\nBlorb Library 1.0 (big-endian)\n"; +#define bb_native2(v) (v) +#define bb_native4(v) (v) +#endif + +#ifdef BLORB_LITTLE_ENDIAN +static char contentsticker[] = "\nBlorb Library 1.0 (little-endian)\n"; +#define bb_native2(v) \ + ( (((uint16)(v) >> 8) & 0x00ff) \ + | (((uint16)(v) << 8) & 0xff00)) +#define bb_native4(v) \ + ( (((uint32)(v) >> 24) & 0x000000ff) \ + | (((uint32)(v) >> 8) & 0x0000ff00) \ + | (((uint32)(v) << 8) & 0x00ff0000) \ + | (((uint32)(v) << 24) & 0xff000000)) +#endif + +#ifdef CRAPOLA +#ifndef bb_native4 +#error "You must define either BLORB_BIG_ENDIAN" +#error "or BLORB_LITTLE_ENDIAN in blorb.h in order" +#error "to compile this library." +#endif +#endif /* CRAPOLA */ + +static int lib_inited = FALSE; + +static bb_err_t bb_initialize_map(bb_map_t *map); +static bb_err_t bb_initialize(void); +static int sortsplot(const void *p1, const void *p2); + +/* Do some one-time startup tests. */ +static bb_err_t bb_initialize() +{ + union { + uint32 val; + unsigned char ch[4]; + } test; + uint32 val; + + if (sizeof(uint32) != 4 || sizeof(uint16) != 2) + return bb_err_CompileTime; /* Basic types are the wrong size. */ + + test.ch[0] = 0x13; + test.ch[1] = 0x57; + test.ch[2] = 0x9a; + test.ch[3] = 0xce; + val = test.val; + if (bb_native4(val) != 0x13579ace) + return bb_err_CompileTime; /* Wrong endianness. */ + + return bb_err_None; +} + +bb_err_t bb_create_map(FILE *file, bb_map_t **newmap) +{ + bb_err_t err; + bb_map_t *map; + size_t readlen; + uint32 nextpos, totallength; + bb_chunkdesc_t *chunks; + int chunks_size, numchunks; + uint32 buffer[4]; + + *newmap = NULL; + + if (!lib_inited) { + err = bb_initialize(); + if (err) + return err; + lib_inited = TRUE; + } + + /* First, chew through the file and index the chunks. */ + + err = fseek(file, 0, 0); + if (err) + return bb_err_Read; + +/* FIXME. Under 16-bit DOS, this fails. + * From the following url: "'unsigned long' variables don't work in + * 16-bit mode." How do I get around this? + * http://www.digitalmars.com/d/archives/c++/dos/16-bits/45.html + */ + readlen = fread(buffer, sizeof(uint32), 3, file); + if (readlen != 3) + return bb_err_Read; + + if (bb_native4(buffer[0]) != bb_ID_FORM) + return bb_err_Format; + if (bb_native4(buffer[2]) != bb_ID_IFRS) + return bb_err_Format; + + totallength = bb_native4(buffer[1]) + 8; + nextpos = 12; + + chunks_size = 8; + numchunks = 0; + chunks = (bb_chunkdesc_t *)malloc(sizeof(bb_chunkdesc_t) * chunks_size); + + while (nextpos < totallength) { + uint32 type, len; + int chunum; + bb_chunkdesc_t *chu; + + err = fseek(file, nextpos, 0); + if (err) + return bb_err_Read; + + readlen = fread(buffer, sizeof(uint32), 2, file); + if (readlen != 2) + return bb_err_Read; + + type = bb_native4(buffer[0]); + len = bb_native4(buffer[1]); + + if (numchunks >= chunks_size) { + chunks_size *= 2; + chunks = (bb_chunkdesc_t *)realloc(chunks, + sizeof(bb_chunkdesc_t) * chunks_size); + } + + chunum = numchunks; + chu = &(chunks[chunum]); + numchunks++; + + chu->type = type; + chu->startpos = nextpos; + if (type == bb_ID_FORM) { + chu->datpos = nextpos; + chu->len = len+8; + } + else { + chu->datpos = nextpos+8; + chu->len = len; + } + chu->ptr = NULL; + chu->auxdatnum = -1; + + nextpos = nextpos + len + 8; + if (nextpos & 1) + nextpos++; + + if (nextpos > totallength) + return bb_err_Format; + } + + /* The basic IFF structure seems to be ok, and we have a list of + chunks. Now we allocate the map structure itself. */ + + map = (bb_map_t *)malloc(sizeof(bb_map_t)); + if (!map) { + free(chunks); + return bb_err_Alloc; + } + + map->inited = bb_Inited_Magic; + map->file = file; + map->chunks = chunks; + map->numchunks = numchunks; + map->resources = NULL; + map->ressorted = NULL; + map->numresources = 0; + map->releasenum = 0; + map->zheader = NULL; + map->resolution = NULL; + map->palettechunk = -1; + map->palette = NULL; + map->auxsound = NULL; + map->auxpict = NULL; + + /* Now we do everything else involved in loading the Blorb file, + such as building resource lists. */ + + err = bb_initialize_map(map); + if (err) { + bb_destroy_map(map); + return err; + } + + *newmap = map; + return bb_err_None; +} + +static bb_err_t bb_initialize_map(bb_map_t *map) +{ + /* It is important that the map structure be kept valid during this + function. If this returns an error, bb_destroy_map() will be called. */ + + int ix, jx; + bb_result_t chunkres; + bb_err_t err; + uint32 *ptr; + uint32 len; + uint32 val; + int numres; + int gotindex = FALSE; + + for (ix=0; ixnumchunks; ix++) { + bb_chunkdesc_t *chu = &map->chunks[ix]; + + switch (chu->type) { + + case bb_ID_RIdx: + /* Resource index chunk: build the resource list and sort it. */ + + if (gotindex) + return bb_err_Format; /* duplicate index chunk */ + err = bb_load_chunk_by_number(map, bb_method_Memory, + &chunkres, ix); + if (err) + return err; + + ptr = chunkres.data.ptr; + len = chunkres.length; + val = ptr[0]; + numres = bb_native4(val); + + if (numres) { + int ix2; + bb_resdesc_t *resources; + bb_resdesc_t **ressorted; + + if (len != numres*12+4) + return bb_err_Format; /* bad length field */ + + resources = (bb_resdesc_t *)malloc(numres * sizeof(bb_resdesc_t)); + ressorted = (bb_resdesc_t **)malloc(numres * sizeof(bb_resdesc_t *)); + if (!ressorted || !resources) + return bb_err_Alloc; + + ix2 = 0; + for (jx=0; jxusage = bb_native4(val); + val = ptr[2+jx*3]; + res->resnum = bb_native4(val); + val = ptr[3+jx*3]; + respos = bb_native4(val); + + while (ix2 < map->numchunks && map->chunks[ix2].startpos < respos) + ix2++; + + if (ix2 >= map->numchunks || map->chunks[ix2].startpos != respos) + return bb_err_Format; /* start pos does not match a real chunk */ + + res->chunknum = ix2; + + ressorted[jx] = res; + } + + /* Sort a resource list (actually a list of pointers to structures + in map->resources.) This makes it easy to find resources by + usage and resource number. */ + qsort(ressorted, numres, sizeof(bb_resdesc_t *), + &sortsplot); + + map->numresources = numres; + map->resources = resources; + map->ressorted = ressorted; + } + + bb_unload_chunk(map, ix); + gotindex = TRUE; + break; + + case bb_ID_RelN: + /* Release number chunk: Get the release number. */ + + err = bb_load_chunk_by_number(map, bb_method_Memory, + &chunkres, ix); + if (err) + return err; + + if (chunkres.length != 2) + return bb_err_Format; + + { + uint16 val = *((uint16 *)chunkres.data.ptr); + map->releasenum = bb_native2(val); + } + + bb_unload_chunk(map, ix); + break; + + case bb_ID_IFhd: + /* Z-header chunk: Get the header info. */ + + err = bb_load_chunk_by_number(map, bb_method_Memory, + &chunkres, ix); + if (err) + return err; + + if (chunkres.length < 13) + return bb_err_Format; + + { + uint16 val; + bb_zheader_t *head = (bb_zheader_t *)malloc(sizeof(bb_zheader_t)); + if (!head) + return bb_err_Alloc; + + val = ((uint16 *)(chunkres.data.ptr))[0]; + head->releasenum = bb_native2(val); + + val = ((uint16 *)(chunkres.data.ptr))[4]; + head->checksum = bb_native2(val); + + for (jx=0; jx<6; jx++) { + head->serialnum[jx] = ((char *)(chunkres.data.ptr))[2+jx]; + } + + map->zheader = head; + } + + bb_unload_chunk(map, ix); + break; + + case bb_ID_Reso: + /* Resolution chunk: Get the window size data, and resolution + ratios for images. */ + + err = bb_load_chunk_by_number(map, bb_method_Memory, + &chunkres, ix); + if (err) + return err; + + if (chunkres.length < 24) + return bb_err_Format; + + ptr = chunkres.data.ptr; + len = chunkres.length; + + { + bb_resolution_t *reso = (bb_resolution_t *)malloc(sizeof(bb_resolution_t)); + if (!reso) + return bb_err_Alloc; + + reso->px = bb_native4(ptr[0]); + reso->py = bb_native4(ptr[1]); + reso->minx = bb_native4(ptr[2]); + reso->miny = bb_native4(ptr[3]); + reso->maxx = bb_native4(ptr[4]); + reso->maxy = bb_native4(ptr[5]); + + map->resolution = reso; + } + + ptr += 6; + len -= 6*4; + + len = len / 28; + + if (len) { + bb_aux_pict_t *aux = (bb_aux_pict_t *)malloc(len * sizeof(bb_aux_pict_t)); + + for (jx=0; jxchunks[res.chunknum]); + if (chu->auxdatnum != -1) + return bb_err_Format; /* two image entries for this resource */ + chu->auxdatnum = jx; + aux[jx].ratnum = bb_native4(ptr[1]); + aux[jx].ratden = bb_native4(ptr[2]); + aux[jx].minnum = bb_native4(ptr[3]); + aux[jx].minden = bb_native4(ptr[4]); + aux[jx].maxnum = bb_native4(ptr[5]); + aux[jx].maxden = bb_native4(ptr[6]); + } + } + + map->auxpict = aux; + } + + bb_unload_chunk(map, ix); + break; + + case bb_ID_Loop: + /* Looping chunk: Get looping data for sounds. */ + + err = bb_load_chunk_by_number(map, bb_method_Memory, + &chunkres, ix); + if (err) + return err; + + ptr = chunkres.data.ptr; + len = chunkres.length; + + len = len / 8; + + if (len) { + bb_aux_sound_t *aux = (bb_aux_sound_t *)malloc(len * sizeof(bb_aux_sound_t)); + + for (jx=0; jxchunks[res.chunknum]); + if (chu->auxdatnum != -1) + return bb_err_Format; /* two looping entries for this resource */ + chu->auxdatnum = jx; + aux[jx].repeats = bb_native4(ptr[1]); + } + } + + map->auxsound = aux; + } + + bb_unload_chunk(map, ix); + break; + + case bb_ID_Plte: + /* Palette chunk: Don't get the palette info now, since it may + be large and the interpreter may not care. But remember + the chunk number in case the interpreter asks later. */ + + map->palettechunk = ix; + break; + } + } + + return bb_err_None; +} + +bb_err_t bb_destroy_map(bb_map_t *map) +{ + int ix; + + if (!map || !map->chunks || map->inited != bb_Inited_Magic) + return bb_err_NotAMap; + + for (ix=0; ixnumchunks; ix++) { + bb_chunkdesc_t *chu = &(map->chunks[ix]); + if (chu->ptr) { + free(chu->ptr); + chu->ptr = NULL; + } + } + + if (map->chunks) { + free(map->chunks); + map->chunks = NULL; + } + + map->numchunks = 0; + + if (map->resources) { + free(map->resources); + map->resources = NULL; + } + + if (map->ressorted) { + free(map->ressorted); + map->ressorted = NULL; + } + + map->numresources = 0; + + if (map->zheader) { + free(map->zheader); + map->zheader = NULL; + } + + if (map->resolution) { + free(map->resolution); + map->resolution = NULL; + } + + if (map->palette) { + if (!map->palette->isdirect && map->palette->data.table.colors) { + free(map->palette->data.table.colors); + map->palette->data.table.colors = NULL; + } + free(map->palette); + map->palette = NULL; + } + + if (map->auxsound) { + free(map->auxsound); + map->auxsound = NULL; + } + + if (map->auxpict) { + free(map->auxpict); + map->auxpict = NULL; + } + + map->file = NULL; + map->inited = 0; + + free(map); + + return bb_err_None; +} + +/* Turn a four-byte constant into a string. This returns a static buffer, + so if you call it twice, the old value gets overwritten. */ +char *bb_id_to_string(uint32 id) +{ + static char buf[5]; + buf[0] = (id >> 24) & 0xff; + buf[1] = (id >> 16) & 0xff; + buf[2] = (id >> 8) & 0xff; + buf[3] = (id) & 0xff; + buf[4] = '\0'; + return buf; +} + +/* Turn an error code into a string describing the error. */ +char *bb_err_to_string(bb_err_t err) +{ + switch (err) { + case bb_err_None: + return "ok"; + case bb_err_CompileTime: + return "library compiled wrong"; + case bb_err_Alloc: + return "cannot allocate memory"; + case bb_err_Read: + return "cannot read from file"; + case bb_err_NotAMap: + return "map structure is bad"; + case bb_err_Format: + return "bad format in Blorb file"; + case bb_err_NotFound: + return "data not found"; + default: + return "unknown error"; + } +} + +/* This is used for binary searching and quicksorting the resource pointer list. */ +static int sortsplot(const void *p1, const void *p2) +{ + bb_resdesc_t *v1 = *(bb_resdesc_t **)p1; + bb_resdesc_t *v2 = *(bb_resdesc_t **)p2; + if (v1->usage < v2->usage) + return -1; + if (v1->usage > v2->usage) + return 1; + return v1->resnum - v2->resnum; +} + +bb_err_t bb_load_chunk_by_type(bb_map_t *map, int method, bb_result_t *res, + uint32 type, int count) +{ + int ix; + + for (ix=0; ix < map->numchunks; ix++) { + if (map->chunks[ix].type == type) { + if (count == 0) + break; + count--; + } + } + + if (ix >= map->numchunks) { + return bb_err_NotFound; + } + + return bb_load_chunk_by_number(map, method, res, ix); +} + +bb_err_t bb_load_chunk_by_number(bb_map_t *map, int method, bb_result_t *res, + int chunknum) +{ + bb_chunkdesc_t *chu; + + if (chunknum < 0 || chunknum >= map->numchunks) + return bb_err_NotFound; + + chu = &(map->chunks[chunknum]); + + switch (method) { + + case bb_method_DontLoad: + /* do nothing */ + break; + + case bb_method_FilePos: + res->data.startpos = chu->datpos; + break; + + case bb_method_Memory: + if (!chu->ptr) { + bb_err_t err; + size_t readlen; + void *dat = malloc(chu->len); + + if (!dat) + return bb_err_Alloc; + + err = fseek(map->file, chu->datpos, 0); + if (err) + return bb_err_Read; + + readlen = fread(dat, 1, chu->len, map->file); + if (readlen != chu->len) + return bb_err_Read; + + chu->ptr = dat; + } + res->data.ptr = chu->ptr; + break; + } + + res->chunknum = chunknum; + res->length = chu->len; + + return bb_err_None; +} + +bb_err_t bb_load_resource(bb_map_t *map, int method, bb_result_t *res, + uint32 usage, int resnum) +{ + bb_resdesc_t sample; + bb_resdesc_t *ptr; + bb_resdesc_t **found; + + sample.usage = usage; + sample.resnum = resnum; + ptr = &sample; + + found = bsearch(&ptr, map->ressorted, map->numresources, sizeof(bb_resdesc_t *), + &sortsplot); + + if (!found) + return bb_err_NotFound; + + return bb_load_chunk_by_number(map, method, res, (*found)->chunknum); +} + +bb_err_t bb_unload_chunk(bb_map_t *map, int chunknum) +{ + bb_chunkdesc_t *chu; + + if (chunknum < 0 || chunknum >= map->numchunks) + return bb_err_NotFound; + + chu = &(map->chunks[chunknum]); + + if (chu->ptr) { + free(chu->ptr); + chu->ptr = NULL; + } + + return bb_err_None; +} + +bb_err_t bb_count_resources(bb_map_t *map, uint32 usage, + int *num, int *min, int *max) +{ + int ix; + int count, minval, maxval, val; + + count = 0; + minval = 0; + maxval = 0; + + for (ix=0; ixnumresources; ix++) { + if (map->resources[ix].usage == usage) { + val = map->resources[ix].resnum; + if (count == 0) { + count++; + minval = val; + maxval = val; + } + else { + count++; + if (val < minval) + minval = val; + if (val > maxval) + maxval = val; + } + } + } + + if (num) + *num = count; + if (min) + *min = minval; + if (max) + *max = maxval; + + return bb_err_None; +} + +uint16 bb_get_release_num(bb_map_t *map) +{ + return map->releasenum; +} + +bb_zheader_t *bb_get_zheader(bb_map_t *map) +{ + return map->zheader; +} + +bb_resolution_t *bb_get_resolution(bb_map_t *map) +{ + return map->resolution; +} + +bb_err_t bb_get_palette(bb_map_t *map, bb_palette_t **res) +{ + int ix; + bb_err_t err; + + if (res) + *res = NULL; + + if (map->palettechunk < 0) { + return bb_err_None; + } + + if (!map->palette) { + bb_result_t chunkres; + bb_palette_t *pal; + unsigned char *ptr; + + pal = (bb_palette_t *)malloc(sizeof(bb_palette_t)); + if (!pal) + return bb_err_Alloc; + + err = bb_load_chunk_by_number(map, bb_method_Memory, &chunkres, + map->palettechunk); + if (err) + return err; + + ptr = chunkres.data.ptr; + + if (chunkres.length == 1) { + int val = ptr[0]; + if (val != 16 && val != 32) + return bb_err_Format; + pal->isdirect = TRUE; + pal->data.depth = val; + } + else { + int size = chunkres.length / 3; + bb_color_t *colors = (bb_color_t *)malloc(size * sizeof(bb_color_t)); + if (!colors) + return bb_err_Alloc; + if (size < 1 || size > 256) + return bb_err_Format; + for (ix=0; ixisdirect = FALSE; + pal->data.table.numcolors = size; + pal->data.table.colors = colors; + } + + bb_unload_chunk(map, map->palettechunk); + map->palette = pal; + } + + if (res) + *res = map->palette; + return bb_err_None; +} + +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 err; + + if (auxdata) + *auxdata = NULL; + + err = bb_load_resource(map, method, res, bb_ID_Pict, resnum); + if (err) + return err; + + if (auxdata) { + bb_chunkdesc_t *chu = &(map->chunks[res->chunknum]); + if (chu->auxdatnum >= 0 && map->auxpict) { + *auxdata = &(map->auxpict[chu->auxdatnum]); + } + } + + return bb_err_None; +} + +bb_err_t bb_load_resource_snd(bb_map_t *map, int method, bb_result_t *res, + int resnum, bb_aux_sound_t **auxdata) +{ + bb_err_t err; + + if (auxdata) + *auxdata = NULL; + +/* err = bb_load_resource(map, method, res, bb_ID_Pict, resnum); */ + err = bb_load_resource(map, method, res, bb_ID_Snd, resnum); + if (err) + return err; + + if (auxdata) { + bb_chunkdesc_t *chu = &(map->chunks[res->chunknum]); + if (chu->auxdatnum >= 0 && map->auxsound) { + *auxdata = &(map->auxsound[chu->auxdatnum]); + } + } + + return bb_err_None; +} + diff --git a/src/dos/bcinit.c b/src/dos/bcinit.c index 247e4b0..e70355a 100644 --- a/src/dos/bcinit.c +++ b/src/dos/bcinit.c @@ -940,7 +940,7 @@ int dos_init_blorb(void) */ blorb_err = bb_load_chunk_by_type(blorb_map, bb_method_FilePos, - &blorb_res, bb_make_id('Z','C','O','D'), 0); + &blorb_res, bb_ID_ZCOD, 0); if (blorb_err == bb_err_None) { exec_in_blorb = 1; diff --git a/src/dos/blorb.h b/src/dos/blorb.h new file mode 100644 index 0000000..5a0694c --- /dev/null +++ b/src/dos/blorb.h @@ -0,0 +1,152 @@ +#ifndef BLORB_H +#define BLORB_H + +/* blorb.h: Header file for Blorb library, version 1.0.2. + Designed by Andrew Plotkin + http://www.eblong.com/zarf/blorb/index.html + + This is the header that a Z-machine interpreter should include. + It defines everything that the interpreter has to know. +*/ + +/* Things you (the porter) have to edit: */ + +/* As you might expect, uint32 must be a 32-bit unsigned numeric type, + and uint16 a 16-bit unsigned numeric type. You should also uncomment + exactly one of the two ENDIAN definitions. */ + +/* #define BLORB_BIG_ENDIAN */ + +#define BLORB_LITTLE_ENDIAN +typedef unsigned long uint32; +typedef unsigned short uint16; + +/* End of things you have to edit. */ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* Error type and error codes */ +typedef int bb_err_t; + +#define bb_err_None (0) +#define bb_err_CompileTime (1) +#define bb_err_Alloc (2) +#define bb_err_Read (3) +#define bb_err_NotAMap (4) +#define bb_err_Format (5) +#define bb_err_NotFound (6) + +/* Methods for loading a chunk */ +#define bb_method_DontLoad (0) +#define bb_method_Memory (1) +#define bb_method_FilePos (2) + +/* Four-byte constants */ + +/*#define bb_make_id(c1, c2, c3, c4) \ + (((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4)) +*/ +#define bb_ID_Snd 1399743520 +#define bb_ID_Exec 1165518179 +#define bb_ID_Pict 1349084020 +#define bb_ID_Copyright 677587232 +#define bb_ID_AUTH 1096111176 +#define bb_ID_ANNO 1095650895 + +#define bb_ID_ZCOD 1514360644 + +/* bb_result_t: Result when you try to load a chunk. */ +typedef struct bb_result_struct { + int chunknum; /* The chunk number (for use in bb_unload_chunk(), etc.) */ + union { + void *ptr; /* A pointer to the data (if you used bb_method_Memory) */ + uint32 startpos; /* The position in the file (if you used bb_method_FilePos) */ + } data; + uint32 length; /* The length of the data */ +} bb_result_t; + +/* bb_aux_sound_t: Extra data which may be associated with a sound. */ +typedef struct bb_aux_sound_struct { + char repeats; +} bb_aux_sound_t; + +/* bb_aux_pict_t: Extra data which may be associated with an image. */ +typedef struct bb_aux_pict_struct { + uint32 ratnum, ratden; + uint32 minnum, minden; + uint32 maxnum, maxden; +} bb_aux_pict_t; + +/* bb_resolution_t: The global resolution data. */ +typedef struct bb_resolution_struct { + uint32 px, py; + uint32 minx, miny; + uint32 maxx, maxy; +} bb_resolution_t; + +/* bb_color_t: Guess what. */ +typedef struct bb_color_struct { + unsigned char red, green, blue; +} bb_color_t; + +/* bb_palette_t: The palette data. */ +typedef struct bb_palette_struct { + int isdirect; + union { + int depth; /* The depth (if isdirect is TRUE). Either 16 or 32. */ + struct { + int numcolors; + bb_color_t *colors; + } table; /* The list of colors (if isdirect is FALSE). */ + } data; +} bb_palette_t; + +/* bb_zheader_t: Information to identify a Z-code file. */ +typedef struct bb_zheader_struct { + uint16 releasenum; /* Bytes $2-3 of header. */ + char serialnum[6]; /* Bytes $12-17 of header. */ + uint16 checksum; /* Bytes $1C-1D of header. */ + /* The initpc field is not used by Blorb. */ +} bb_zheader_t; + +/* bb_map_t: Holds the complete description of an open Blorb file. + This type is opaque for normal interpreter use. */ +typedef struct bb_map_struct bb_map_t; + +/* Function declarations. These functions are of fairly general use; + they would apply to any Blorb file. */ + +extern bb_err_t bb_create_map(FILE *file, bb_map_t **newmap); +extern bb_err_t bb_destroy_map(bb_map_t *map); + +extern char *bb_err_to_string(bb_err_t err); + +extern bb_err_t bb_load_chunk_by_type(bb_map_t *map, int method, + bb_result_t *res, uint32 chunktype, int count); +extern bb_err_t bb_load_chunk_by_number(bb_map_t *map, int method, + bb_result_t *res, int chunknum); +extern bb_err_t bb_unload_chunk(bb_map_t *map, int chunknum); + +extern bb_err_t bb_load_resource(bb_map_t *map, int method, + bb_result_t *res, uint32 usage, int resnum); +extern bb_err_t bb_count_resources(bb_map_t *map, uint32 usage, + int *num, int *min, int *max); + +/* More function declarations. These functions are more or less + specific to the Z-machine's use of Blorb. */ + +extern uint16 bb_get_release_num(bb_map_t *map); +extern bb_zheader_t *bb_get_zheader(bb_map_t *map); +extern bb_resolution_t *bb_get_resolution(bb_map_t *map); +extern bb_err_t bb_get_palette(bb_map_t *map, bb_palette_t **res); +extern bb_err_t bb_load_resource_pict(bb_map_t *map, int method, + bb_result_t *res, int resnum, bb_aux_pict_t **auxdata); +extern bb_err_t bb_load_resource_snd(bb_map_t *map, int method, + bb_result_t *res, int resnum, bb_aux_sound_t **auxdata); + +#endif /* BLORB_H */ diff --git a/src/dos/blorblow.h b/src/dos/blorblow.h new file mode 100644 index 0000000..f3ccf55 --- /dev/null +++ b/src/dos/blorblow.h @@ -0,0 +1,72 @@ +#ifndef BLORBLOW_H +#define BLORBLOW_H + +/* blorblow.h: Low-level header file for Blorb library, version 1.0.2. + Designed by Andrew Plotkin + http://www.eblong.com/zarf/blorb/index.html + + This header is generally of interest only to the Blorb library code + itself (blorblib.c); it defines things internal to the library. + An interpreter shouldn't have to include this file. The only time you + might need to include this is if you're writing a Blorb file analysis + tool (such as blorbscan), or a transformation tool, or some such thing. +*/ + +/* More four-byte constants. */ + +#define bb_ID_FORM 1179603533 +#define bb_ID_IFRS 1229345363 +#define bb_ID_RIdx 1380541560 +#define bb_ID_IFhd 1229351012 +#define bb_ID_Reso 1382380399 +#define bb_ID_Loop 1282371440 +#define bb_ID_RelN 1382378574 +#define bb_ID_Plte 1349284965 + +/* bb_chunkdesc_t: Describes one chunk of the Blorb file. */ +typedef struct bb_chunkdesc_struct { + uint32 type; + uint32 len; + uint32 startpos; /* start of chunk header */ + uint32 datpos; /* start of data (either startpos or startpos+8) */ + + void *ptr; /* pointer to malloc'd data, if loaded */ + int auxdatnum; /* entry in the auxsound/auxpict array; -1 if none. + This only applies to chunks that represent resources; */ + +} bb_chunkdesc_t; + +/* bb_resdesc_t: Describes one resource in the Blorb file. */ +typedef struct bb_resdesc_struct { + uint32 usage; + int resnum; + int chunknum; +} bb_resdesc_t; + +/* bb_map_t: Holds the complete description of an open Blorb file. */ +struct bb_map_struct { + uint32 inited; /* holds bb_Inited_Magic if the map structure is valid */ + FILE *file; + + int numchunks; + bb_chunkdesc_t *chunks; /* list of chunk descriptors */ + + int numresources; + bb_resdesc_t *resources; /* list of resource descriptors */ + bb_resdesc_t **ressorted; /* list of pointers to descriptors + in map->resources -- sorted by usage and resource number. */ + + bb_zheader_t *zheader; + int releasenum; + bb_resolution_t *resolution; + int palettechunk; /* chunk number of palette, or -1 if there is none. */ + bb_palette_t *palette; + bb_aux_sound_t *auxsound; /* extra information about sounds */ + bb_aux_pict_t *auxpict; /* extra information about pictures */ +}; + +#define bb_Inited_Magic (0xB7012BED) + +extern char *bb_id_to_string(uint32 id); + +#endif /* BLORBLOW_H */ -- 2.34.1