Added Blorbified V6 semi-support to dumb interface.
authorDavid Griffith <dave@661.org>
Sun, 21 Jul 2019 23:28:27 +0000 (16:28 -0700)
committerDavid Griffith <dave@661.org>
Mon, 22 Jul 2019 00:35:47 +0000 (17:35 -0700)
src/dumb/dumb_blorb.c
src/dumb/dumb_frotz.h
src/dumb/dumb_init.c
src/dumb/dumb_pic.c

index 4227c9c7049bd5da4ae570ab7e4890fcc87a99ac..267a4f0b238df8016662570a209368e4d2815d96 100644 (file)
@@ -39,7 +39,7 @@ f_setup_t f_setup;
 
 FILE *blorb_fp;
 bb_result_t blorb_res;
-/* bb_map_t *blorb_map; */     /* Used only locally */
+bb_map_t *blorb_map;
 
 static int isblorb(FILE *);
 
@@ -67,8 +67,6 @@ bb_err_t dumb_blorb_init(char *filename)
 
     bb_err_t blorb_err;
 
-    bb_map_t *blorb_map = NULL;
-
     if ((fp = fopen(filename, "rb")) == NULL)
        return bb_err_Read;
 
@@ -77,41 +75,37 @@ bb_err_t dumb_blorb_init(char *filename)
      */
     if (isblorb(fp)) {                 /* Now we know to look */
        f_setup.exec_in_blorb = 1;      /* for zcode in the blorb */
-        blorb_fp = fopen(filename, "rb");
+        blorb_fp = fp;
     } 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 = strrchr(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 (f_setup.blorb_file != NULL)
            mystring = strdup(f_setup.blorb_file);
        else {
-           if ((blorb_fp = fopen(mystring, "rb")) == NULL) {
-               p = strrchr(mystring, '.');
-               if (p != NULL)
-                   *p = '\0';
-               strncat(mystring, EXT_BLORB3, len2 * sizeof(char));
-               blorb_fp = fopen(mystring, "rb");
-           }
+           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 = strrchr(mystring, '.');
+           if (p != NULL) *p = '\0';
+           strncat(mystring, EXT_BLORB, len1 * sizeof(char));
        }
 
-       if (blorb_fp == NULL || !isblorb(fp))   /* No matching blorbs found. */
-           return bb_err_NoBlorb;
+       /* Check if foo.blb is there. */
+       if ((fp = fopen(mystring, "rb")) == NULL) {
+           p = strrchr(mystring, '.');
+           if (p != NULL) *p = '\0';
+           strncat(mystring, EXT_BLORB3, len2 * sizeof(char));
 
+           if (!(fp = fopen(mystring, "rb")))
+               return bb_err_NoBlorb;
+       }
+       if (!isblorb(fp)) {
+           fclose(fp);
+           return bb_err_NoBlorb;
+       }
        /* At this point we know that we're using a naked zcode file */
        /* with resources in a separate Blorb file. */
+       blorb_fp = fp;
        f_setup.use_blorb = 1;
     }
 
@@ -119,7 +113,7 @@ bb_err_t dumb_blorb_init(char *filename)
      * 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);
+    blorb_err = bb_create_map(blorb_fp, &blorb_map);
     if (blorb_err != bb_err_None)
        return bb_err_Format;
 
@@ -132,37 +126,15 @@ bb_err_t dumb_blorb_init(char *filename)
        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)
 {
index 4da1d808a8b59add491252f175882a8d74d4a878..27cd681482cd110fbef070ae48df5e7965f07ea0 100644 (file)
@@ -41,4 +41,4 @@ void dumb_elide_more_prompt(void);
 void dumb_set_picture_cell(int row, int col, zchar c);
 
 /* dumb-pic.c */
-void dumb_init_pictures(char *graphics_filename);
+bool dumb_init_pictures(void);
index 08e32a0a08d740e222e4feea99fce257e13394a9..86289696acc049986e2b5eff4b149bed31f302b5 100644 (file)
@@ -88,7 +88,6 @@ static int user_screen_width = 75;
 static int user_screen_height = 24;
 static int user_random_seed = -1;
 static int user_tandy_bit = 0;
-static char *graphics_filename = NULL;
 static bool plain_ascii = FALSE;
 
 /*
@@ -208,7 +207,7 @@ void os_init_screen(void)
 
     dumb_init_input();
     dumb_init_output();
-    dumb_init_pictures(graphics_filename);
+    dumb_init_pictures();
 }
 
 int os_random_seed (void)
@@ -238,7 +237,7 @@ FILE *os_load_story(void)
 #ifndef NO_BLORB
     switch (dumb_blorb_init(f_setup.story_file)) {
        case bb_err_NoBlorb:
-//       printf("No blorb file found.\n\n");
+/*       printf("No blorb file found.\n\n"); */
          break;
        case bb_err_Format:
          printf("Blorb file loaded, but unable to build map.\n\n");
@@ -247,7 +246,7 @@ FILE *os_load_story(void)
          printf("Blorb file loaded, but lacks executable chunk.\n\n");
          break;
        case bb_err_None:
-//       printf("No blorb errors.\n\n");
+/*       printf("No blorb errors.\n\n"); */
          break;
     }
 
index ee140774c9361d7501027bcd66da843883cbf0c3..55c7dec562571ff1ea3d7b1944aa2b4e1a91e5a4 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "dumb_frotz.h"
+#include "dumb_blorb.h"
 
 f_setup_t f_setup;
 
@@ -32,79 +33,128 @@ f_setup_t f_setup;
 #define PIC_HEADER_WIDTH 2
 #define PIC_HEADER_HEIGHT 4
 
+bb_map_t *blorb_map;
+
 static struct {
     int z_num;
     int width;
     int height;
     int orig_width;
     int orig_height;
+    uint32 type;
 } *pict_info;
 static int num_pictures = 0;
 
-static unsigned char lookupb(unsigned char *p, int n) {return p[n];}
-static unsigned short lookupw(unsigned char *p, int n)
+
+static int round_div(int x, int y)
 {
-    return (p[n + 1] << 8) | p[n];
+    int quotient = x / y;
+    int dblremain = (x % y) << 1;
+
+    if ((dblremain > y) || ((dblremain == y) && (quotient & 1)))
+       quotient++;
+    return quotient;
 }
 
-void dumb_init_pictures (char *filename)
+
+bool dumb_init_pictures (void)
 {
-    FILE *file = NULL;
-    int success = FALSE;
-    unsigned char gheader[16];
-    unsigned char *raw_info = NULL;
-    int i, entry_size, flags;
-    float x_scaler, y_scaler;
-
-    do {
-       if ((h_version != V6)
-           || !filename
-           || ((file = fopen (filename, "rb")) == NULL)
-           || (fread(&gheader, sizeof (gheader), 1, file) != 1))
-           break;
-
-       num_pictures = lookupw(gheader, PIC_FILE_HEADER_NUM_IMAGES);
-       entry_size = lookupb(gheader, PIC_FILE_HEADER_ENTRY_SIZE);
-       flags = lookupb(gheader, PIC_FILE_HEADER_FLAGS);
-
-       raw_info = malloc(num_pictures * entry_size);
-
-       if (fread(raw_info, num_pictures * entry_size, 1, file) != 1)
-           break;
-
-       pict_info = malloc((num_pictures + 1) * sizeof(*pict_info));
-       pict_info[0].z_num = 0;
-       pict_info[0].height = num_pictures;
-       pict_info[0].width = lookupw(gheader, PIC_FILE_HEADER_VERSION);
-
-       y_scaler = h_screen_rows / 200.0;
-       x_scaler = h_screen_cols / ((flags & 0x08) ? 640.0 : 320.0);
-
-       /* Copy and scale.  */
-       for (i = 1; i <= num_pictures; i++) {
-           unsigned char *p = raw_info + entry_size * (i - 1);
-           pict_info[i].z_num = lookupw(p, PIC_HEADER_NUMBER);
-           pict_info[i].orig_height = lookupw(p, PIC_HEADER_HEIGHT);
-           pict_info[i].orig_width = lookupw(p, PIC_HEADER_WIDTH);
-           pict_info[i].height = pict_info[i].orig_height * y_scaler + .5;
-           pict_info[i].width = pict_info[i].orig_width * x_scaler + .5;
-       }
+    int maxlegalpic = 0;
+    int i, x_scale, y_scale;
+    bool success = FALSE;
+
+    unsigned char png_magic[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
+    unsigned char ihdr_name[]  = "IHDR";
+    unsigned char jpg_magic[3] = {0xFF, 0xD8, 0xFF};
+    unsigned char jfif_name[5] = {'J', 'F', 'I', 'F', 0x00};
+
+    bb_result_t res;
+    uint32 pos;
+
+    if (blorb_map == NULL) return FALSE;
+
+    bb_count_resources(blorb_map, bb_ID_Pict, &num_pictures, NULL, &maxlegalpic);
+    pict_info = malloc((num_pictures + 1) * sizeof(*pict_info));
+    pict_info[0].z_num = 0;
+    pict_info[0].height = num_pictures;
+    pict_info[0].width = bb_get_release_num(blorb_map);
+
+    y_scale = 200;
+    x_scale = 320;
+
+    for (i = 1; i <= num_pictures; i++) {
+       if (bb_load_resource(blorb_map, bb_method_Memory, &res, bb_ID_Pict, i) == bb_err_None) {
+           pict_info[i].type = blorb_map->chunks[res.chunknum].type;
+           /* Copy and scale. */
+           pict_info[i].z_num = i;
+           /* Check to see if we're dealing with a PNG file. */
+           if (pict_info[i].type == bb_ID_PNG) {
+               if (memcmp(res.data.ptr, png_magic, 8) == 0) {
+                   /* Check for IHDR chunk.  If it's not there, PNG file is invalid. */
+                   if (memcmp(res.data.ptr+12, ihdr_name, 4) == 0) {
+                       pict_info[i].orig_width =
+                           (*((unsigned char *)res.data.ptr+16) << 24) +
+                           (*((unsigned char *)res.data.ptr+17) << 16) +
+                           (*((unsigned char *)res.data.ptr+18) <<  8) +
+                           (*((unsigned char *)res.data.ptr+19) <<  0);
+                       pict_info[i].orig_height =
+                           (*((unsigned char *)res.data.ptr+20) << 24) +
+                           (*((unsigned char *)res.data.ptr+21) << 16) +
+                           (*((unsigned char *)res.data.ptr+22) <<  8) +
+                           (*((unsigned char *)res.data.ptr+23) <<  0);
+                   }
+               }
+           } else if (pict_info[i].type == bb_ID_Rect) {
+               pict_info[i].orig_width =
+                   (*((unsigned char *)res.data.ptr+0) << 24) +
+                   (*((unsigned char *)res.data.ptr+1) << 16) +
+                   (*((unsigned char *)res.data.ptr+2) <<  8) +
+                   (*((unsigned char *)res.data.ptr+3) <<  0);
+               pict_info[i].orig_height =
+                   (*((unsigned char *)res.data.ptr+4) << 24) +
+                   (*((unsigned char *)res.data.ptr+5) << 16) +
+                   (*((unsigned char *)res.data.ptr+6) <<  8) +
+                   (*((unsigned char *)res.data.ptr+7) <<  0);
+           } else if (pict_info[i].type == bb_ID_JPEG) {
+               if (memcmp(res.data.ptr, jpg_magic, 3) == 0) { /* Is it JPEG? */
+                   if (memcmp(res.data.ptr+6, jfif_name, 5) == 0) { /* Look for JFIF */
+                       pos = 11;
+                       while (pos < res.length) {
+                           pos++;
+                           if (pos >= res.length) break;       /* Avoid segfault */
+                           if (*((unsigned char *)res.data.ptr+pos) != 0xFF) continue;
+                           if (*((unsigned char *)res.data.ptr+pos+1) != 0xC0) continue;
+                           pict_info[i].orig_width =
+                               (*((unsigned char *)res.data.ptr+pos+7)*256) +
+                               *((unsigned char *)res.data.ptr+pos+8);
+                               pict_info[i].orig_height =
+                                   (*((unsigned char *)res.data.ptr+pos+5)*256) +
+                                   *((unsigned char *)res.data.ptr+pos+6);
+                       } /* while */
+                   } /* JFIF */
+               } /* JPEG */
+           }
+       } /* for */
+
+       pict_info[i].height = round_div(pict_info[i].orig_height * h_screen_rows, y_scale);
+       pict_info[i].width = round_div(pict_info[i].orig_width * h_screen_cols, x_scale);
+
+       /* Don't let dimensions get rounded to nothing. */
+       if (pict_info[i].orig_height && !pict_info[i].height)
+           pict_info[1].height = 1;
+       if (pict_info[i].orig_width && !pict_info[i].width)
+           pict_info[i].width = 1;
+
        success = TRUE;
-    } while (0);
-
-       if (file)
-           fclose(file);
-       if (raw_info)
-           free(raw_info);
-       if (success)
-           h_config |= CONFIG_PICTURES;
-       else {
-           h_flags &= ~GRAPHICS_FLAG;
-           if (filename)
-               fprintf(stderr, "Warning: could not read graphics file %s\n", filename);
-       }
+    } /* for */
+
+    if (success) h_config |= CONFIG_PICTURES;
+    else h_flags &= ~GRAPHICS_FLAG;
+
+    return success;
 }
 
+
 /* Convert a Z picture number to an index into pict_info.  */
 static int z_num_to_index(int n)
 {