Now using DOS-specific Blorb code. Now Blorb works in DOS!
authorDavid Griffith <dave@661.org>
Thu, 16 Aug 2012 09:08:47 +0000 (02:08 -0700)
committerDavid Griffith <dave@661.org>
Thu, 16 Aug 2012 09:08:47 +0000 (02:08 -0700)
Makefile.tc
src/dos/bcblorb.c [new file with mode: 0644]
src/dos/bcinit.c
src/dos/blorb.h [new file with mode: 0644]
src/dos/blorblow.h [new file with mode: 0644]

index 957a581cb138c54336ce54e75337b16143dc6224..e385629dfc318e573e7af47d01925b68a4e525f5 100644 (file)
@@ -26,7 +26,8 @@ DOS_OBJECTS =   $(DOS_DIR)\bcinit.o \
                $(DOS_DIR)\bcpic.o \\r
                $(DOS_DIR)\bcsample.o \\r
                $(DOS_DIR)\bcscreen.o \\r
-               $(DOS_DIR)\bctext.o\r
+               $(DOS_DIR)\bctext.o \\r
+               $(DOS_DIR)\bcblorb.o \\r
 \r
 CORE_DIR = src\common\r
 CORE_OBJECTS =  $(CORE_DIR)\buffer.o \\r
@@ -50,24 +51,20 @@ CORE_OBJECTS =  $(CORE_DIR)\buffer.o \
                $(CORE_DIR)\quetzal.o \\r
                $(CORE_DIR)\err.o\r
 \r
-BLORB_DIR = src\blorb\r
-BLORB_OBJECTS = $(BLORB_DIR)\blorblib.o\r
-\r
 .SUFFIXES: .c .o .h\r
 \r
 .c.o:\r
-       $(CC) $(CFLAGS) $(DEFS) -I$(DOS_DIR) -I$(CORE_DIR) -I$(BLORB_DIR) -c -o$@ $<\r
+       $(CC) $(CFLAGS) $(DEFS) -I$(DOS_DIR) -I$(CORE_DIR) -c -o$@ $<\r
        $(TLIB) $(LIBRARY) +-$@\r
 \r
 all:   frotz\r
 \r
 clean:\r
-       $(RM) $(BLORB_DIR)\*.o\r
        $(RM) $(CORE_DIR)\*.o\r
        $(RM) $(DOS_DIR)\*.o\r
        $(RM) *.lib\r
        $(RM) *.exe\r
        $(RM) *.bak\r
 \r
-frotz: $(BLORB_OBJECTS) $(DOS_OBJECTS) $(CORE_OBJECTS)\r
+frotz: $(DOS_OBJECTS) $(CORE_OBJECTS)\r
        $(CC) $(CFLAGS) -e$(BINNAME) $(LIBRARY)\r
diff --git a/src/dos/bcblorb.c b/src/dos/bcblorb.c
new file mode 100644 (file)
index 0000000..0d0578b
--- /dev/null
@@ -0,0 +1,835 @@
+/* blorblib.c: Blorb file reader library, version 1.0.2.
+    Designed by Andrew Plotkin <erkyrath@eblong.com>
+    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 <stdio.h>
+#include <stdlib.h>
+#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; ix<map->numchunks; 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; jx<numres; jx++) {
+                        bb_resdesc_t *res = &(resources[jx]);
+                        uint32 respos;
+
+                        val = ptr[1+jx*3];
+                        res->usage = 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; jx<len; jx++, ptr += 7) {
+                        bb_result_t res;
+
+                        err = bb_load_resource(map, bb_method_DontLoad, &res,
+                            bb_ID_Pict, bb_native4(ptr[0]));
+                        if (!err) {
+                            bb_chunkdesc_t *chu = &(map->chunks[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; jx<len; jx++, ptr += 2) {
+                        bb_result_t res;
+
+                        err = bb_load_resource(map, bb_method_DontLoad, &res,
+                            bb_ID_Snd, bb_native4(ptr[0]));
+                        if (!err) {
+                            bb_chunkdesc_t *chu = &(map->chunks[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; ix<map->numchunks; 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; ix<map->numresources; 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; ix<size; ix++) {
+                colors[ix].red   = ptr[ix*3+0];
+                colors[ix].green = ptr[ix*3+1];
+                colors[ix].blue  = ptr[ix*3+2];
+            }
+            pal->isdirect = 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;
+}
+
index 247e4b03617bad5b2e39ed966a3918036d0cc7ed..e70355ad5951c3f53487c692adbb01783bd01cd2 100644 (file)
@@ -940,7 +940,7 @@ int dos_init_blorb(void)
      */\r
 \r
        blorb_err = bb_load_chunk_by_type(blorb_map, bb_method_FilePos,\r
-                       &blorb_res, bb_make_id('Z','C','O','D'), 0);\r
+                       &blorb_res, bb_ID_ZCOD, 0);\r
 \r
        if (blorb_err == bb_err_None) {\r
            exec_in_blorb = 1;\r
diff --git a/src/dos/blorb.h b/src/dos/blorb.h
new file mode 100644 (file)
index 0000000..5a0694c
--- /dev/null
@@ -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 <erkyrath@eblong.com>
+    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 (file)
index 0000000..f3ccf55
--- /dev/null
@@ -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 <erkyrath@eblong.com>
+    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 */