Added preliminary support for Blorb loading for Dumb interface.
authorDavid Griffith <dave@661.org>
Mon, 27 Feb 2017 04:59:44 +0000 (20:59 -0800)
committerDavid Griffith <dave@661.org>
Mon, 27 Feb 2017 04:59:44 +0000 (20:59 -0800)
In the interest of keeping the dumb interface as simple as possible,
I want to make sure that Blorb support is optional.

Makefile
src/dumb/dumb_blorb.c [new file with mode: 0644]
src/dumb/dumb_blorb.h [new file with mode: 0644]
src/dumb/dumb_init.c

index f374df66fa79fe70d9da209fc57ccab9df61c20d..afa2fee238013c4e472af6831a77a0155e1b3457 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -143,7 +143,8 @@ DUMB_TARGET = $(SRCDIR)/frotz_dumb.a
 DUMB_OBJECT =  $(DUMB_DIR)/dumb_init.o \
                $(DUMB_DIR)/dumb_input.o \
                $(DUMB_DIR)/dumb_output.o \
-               $(DUMB_DIR)/dumb_pic.o
+               $(DUMB_DIR)/dumb_pic.o \
+               $(DUMB_DIR)/dumb_blorb.o
 
 BLORB_DIR = $(SRCDIR)/blorb
 BLORB_TARGET =  $(SRCDIR)/blorblib.a
@@ -174,8 +175,8 @@ else
 endif
 
 dumb:          d$(NAME)
-d$(NAME):      hash $(COMMON_DIR)/defines.h $(COMMON_TARGET) $(DUMB_TARGET)
-       $(CC) -o d$(BINNAME)$(EXTENSION) $(COMMON_TARGET) $(DUMB_TARGET) $(LIB)
+d$(NAME):      hash $(COMMON_DIR)/defines.h $(COMMON_TARGET) $(DUMB_TARGET) $(BLORB_TARGET)
+       $(CC) -o d$(BINNAME)$(EXTENSION) $(COMMON_TARGET) $(DUMB_TARGET) $(BLORB_TARGET) $(LIB)
 
 all:   $(NAME) d$(NAME)
 
diff --git a/src/dumb/dumb_blorb.c b/src/dumb/dumb_blorb.c
new file mode 100644 (file)
index 0000000..6f058cf
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * dumb_blorb.c - Blorb routines
+ *
+ * This file is part of Frotz.
+ *
+ * Frotz is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Frotz is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Or visit http://www.fsf.org/
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <libgen.h>
+#include <math.h>
+
+#include "dumb_frotz.h"
+#include "dumb_blorb.h"
+
+f_setup_t f_setup;
+
+FILE *blorb_fp;
+bb_result_t blorb_res;
+bb_map_t *blorb_map;
+
+static int isblorb(FILE *);
+
+#define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
+
+
+/*
+ * dumb_blorb_init
+ *
+ * Check if we're opening a Blorb file directly.  If not, check
+ * to see if there's a seperate Blorb file that looks like it goes
+ * along with this Zcode file.  If we have a Blorb file one way or the
+ * other, make a Blorb map.  If we opened a Blorb file directly, that
+ * means that our executable is in that file and therefore we will look
+ * for a ZCOD chunk and record its location so os_load_story() can find it.
+ * Make sure the Blorb file is opened and with the file pointer blorb_fp.
+ */
+bb_err_t dumb_blorb_init(char *filename)
+{
+    FILE *fp;
+    char *p;
+    char *mystring;
+    int  len1;
+    int  len2;
+
+    bb_err_t blorb_err;
+
+    blorb_map = NULL;
+
+    if ((fp = fopen(filename, "rb")) == NULL)
+       return bb_err_Read;
+
+    /* Is this really a Blorb file?  If not, maybe we're loading a naked
+     * zcode file and our resources are in a seperate blorb file.
+     */
+    if (isblorb(fp)) {                 /* Now we know to look */
+       f_setup.exec_in_blorb = 1;      /* for zcode in the blorb */
+        blorb_fp = fopen(filename, "rb");
+    } else {
+       len1 = strlen(filename) + strlen(EXT_BLORB);
+       len2 = strlen(filename) + strlen(EXT_BLORB3);
+
+       mystring = malloc(len2 * sizeof(char) + 1);
+        strncpy(mystring, filename, len1 * sizeof(char));
+       p = rindex(mystring, '.');
+       if (p != NULL)
+           *p = '\0';
+
+        strncat(mystring, EXT_BLORB, len1 * sizeof(char));
+
+       /* Done monkeying with the initial file. */
+       fclose(fp);
+       fp = NULL;
+
+       /* Check if foo.blb is there. */
+        if ((blorb_fp = fopen(mystring, "rb")) == NULL) {
+           p = rindex(mystring, '.');
+           if (p != NULL)
+               *p = '\0';
+            strncat(mystring, EXT_BLORB3, len2 * sizeof(char));
+           blorb_fp = fopen(mystring, "rb");
+       }
+
+       if (blorb_fp == NULL || !isblorb(fp))   /* No matching blorbs found. */
+           return bb_err_NoBlorb;
+
+       /* At this point we know that we're using a naked zcode file */
+       /* with resources in a seperate Blorb file. */
+       f_setup.use_blorb = 1;
+    }
+
+    /* Create a Blorb map from this file.
+     * This will fail if the file is not a valid Blorb file.
+     * From this map, we can now pick out any resource we need.
+     */
+    blorb_err = bb_create_map(fp, &blorb_map);
+    if (blorb_err != bb_err_None)
+       return bb_err_Format;
+
+    /* Locate the EXEC chunk within the blorb file and record its
+     * location so os_load_story() can find it.
+     */
+    if (f_setup.exec_in_blorb) {
+       blorb_err = bb_load_chunk_by_type(blorb_map, bb_method_FilePos,
+               &blorb_res, bb_make_id('Z','C','O','D'), 0);
+       f_setup.exec_in_blorb = 1;
+    }
+
+    fclose(fp);
+    return blorb_err;
+}
+
+
+/*
+ * ux_blorb_stop
+ *
+ * Basically just close the Blorb file.
+ *
+ */
+void ux_blorb_stop(void)
+{
+    if (blorb_fp != NULL)
+       fclose(blorb_fp);
+    blorb_fp = NULL;
+}
+
+/*
+ **********************************************
+ * These functions are internal to ux_blorb.c
+ *
+ **********************************************
+ */
+
+/*
+ * isblorb
+ *
+ * Returns 1 if this file is a Blorb file, 0 if not.
+ *
+ * FIXME Is there a potential endian problem here?
+ */
+static int isblorb(FILE *fp)
+{
+    char mybuf[4];
+
+    if (fp == NULL)
+       return 0;
+
+    fread(mybuf, 1, 4, fp);
+    if (strncmp(mybuf, "FORM", 4))
+       return 0;
+
+    fseek(fp, 4, SEEK_CUR);
+    fread(mybuf, 1, 4, fp);
+
+    if (strncmp(mybuf, "IFRS", 4))
+       return 0;
+
+    return 1;
+}
diff --git a/src/dumb/dumb_blorb.h b/src/dumb/dumb_blorb.h
new file mode 100644 (file)
index 0000000..0c52c55
--- /dev/null
@@ -0,0 +1,34 @@
+
+#include "../blorb/blorb.h"
+#include "../blorb/blorblow.h"
+
+
+typedef struct sampledata_struct {
+       unsigned short channels;
+       unsigned long samples;
+       unsigned short bits;
+       double rate;
+} sampledata_t;
+
+
+/*
+ * The bb_result_t struct lacks a few members that would make things a
+ * bit easier.  The myresource struct takes encapsulates the bb_result_t
+ * struct and adds a type member and a filepointer.  I would like to
+ * convince Andrew Plotkin to make a change in the reference Blorb code
+ * to add these members.
+ *
+ */
+typedef struct {
+    bb_result_t bbres;
+    ulong type;
+    FILE *fp;
+} myresource;
+
+extern bb_err_t         blorb_err;
+extern bb_map_t         *blorb_map;
+extern bb_result_t      blorb_res;
+extern FILE *blorb_fp;
+
+bb_err_t dumb_blorb_init(char *);
+void dumb_blorb_stop(void);
index 76c7484dc3ff770cfcbcdb60d31343481e9b7653..8b2cc7b135a2ff014fe22e4d9e74a67d742b96db 100644 (file)
@@ -19,7 +19,9 @@
  * Or visit http://www.fsf.org/
  */
 
+#include <libgen.h>
 #include "dumb_frotz.h"
+#include "dumb_blorb.h"
 
 f_setup_t f_setup;
 
@@ -208,7 +210,30 @@ void os_fatal (const char *s, ...)
 
 FILE *os_load_story(void)
 {
-    return fopen(f_setup.story_file, "rb");
+    FILE *fp;
+
+    switch (dumb_blorb_init(f_setup.story_file)) {
+       case bb_err_NoBlorb:
+//       printf("No blorb file found.\n\n");
+         break;
+       case bb_err_Format:
+         printf("Blorb file loaded, but unable to build map.\n\n");
+         break;
+       case bb_err_NotFound:
+         printf("Blorb file loaded, but lacks executable chunk.\n\n");
+         break;
+       case bb_err_None:
+//       printf("No blorb errors.\n\n");
+         break;
+    }
+
+    fp = fopen(f_setup.story_file, "rb");
+
+    /* Is this a Blorb file containing Zcode? */
+    if (f_setup.exec_in_blorb)
+        fseek(fp, blorb_res.data.startpos, SEEK_SET);
+
+    return fp;
 }
 
 /*