Merge branch 'master' into browser
[projects/chimara/chimara.git] / babel / blorb.c
diff --git a/babel/blorb.c b/babel/blorb.c
new file mode 100644 (file)
index 0000000..ebb84e4
--- /dev/null
@@ -0,0 +1,245 @@
+/* blorb.c      Babel interface to blorb files\r
+ * Copyright 2006 by L. Ross Raszewski\r
+ *\r
+ * This code is freely usable for all purposes.\r
+ *\r
+ * This work is licensed under the Creative Commons Attribution2.5 License.\r
+ * To view a copy of this license, visit\r
+ * http://creativecommons.org/licenses/by/2.5/ or send a letter to\r
+ * Creative Commons,\r
+ * 543 Howard Street, 5th Floor,\r
+ * San Francisco, California, 94105, USA.\r
+ *\r
+ * This file depends upon treaty_builder.h, misc.c and ifiction.c\r
+ *\r
+ * Header note: to add support for new executable chunk types, see\r
+ * TranslateExec.\r
+ *\r
+ * This file defines a Treaty of Babel compatable module for handling blorb\r
+ * files.  However, blorb files are not themselves a babel format. This module\r
+ * is used internally by the babel program to handle blorbs.\r
+ *\r
+ * As a result, if GET_STORY_FILE_IFID_SEL returns NO_REPLY_RV,\r
+ * you should check the story file against the babel registry before resorting\r
+ * to the default IFID calculation.\r
+ *\r
+ */\r
+#define FORMAT blorb\r
+#define HOME_PAGE "http://eblong.com/zarf/blorb"\r
+#define FORMAT_EXT ".blorb,.blb,.zblorb,.zlb,.gblorb,.glb"\r
+#define CONTAINER_FORMAT\r
+#include "treaty_builder.h"\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+\r
+extern TREATY treaty_registry[];\r
+/* The following is the translation table of Blorb chunk types to\r
+   babel formats.  it is NULL-terminated. */\r
+static char *TranslateExec[] = { "ZCOD", "zcode",\r
+                                 "GLUL", "glulx",\r
+                                 "TAD2", "tads2",\r
+                                 "TAD3", "tads3",\r
+                                 NULL, NULL };\r
+\r
+void *my_malloc(int32, char *);\r
+int32 ifiction_get_IFID(char *, char *, int32);\r
+\r
+static int32 read_int(void *inp)\r
+{\r
+  unsigned char *mem=(unsigned char *)inp;\r
+  int32 i4 = mem[0],\r
+                    i3 = mem[1],\r
+                    i2 = mem[2],\r
+                    i1 = mem[3];\r
+  return i1 | (i2<<8) | (i3<<16) | (i4<<24);\r
+}\r
+\r
+\r
+static int32 blorb_get_chunk(void *blorb_file, int32 extent, char *id, int32 *begin, int32 *output_extent)\r
+{\r
+ int32 i=12, j;\r
+ while(i<extent-8)\r
+ {\r
+  if (memcmp(((char *)blorb_file)+i,id,4)==0)\r
+  {\r
+   *output_extent=read_int((char *)blorb_file+i+4);\r
+   if (*output_extent > extent) return NO_REPLY_RV;\r
+   *begin=i+8;\r
+   return 1;\r
+  }\r
+\r
+  j=read_int((char *)blorb_file+i+4);\r
+  if (j%2) j++;\r
+  i+=j+8;\r
+\r
+ }\r
+ return NO_REPLY_RV;\r
+}\r
+static int32 blorb_get_resource(void *blorb_file, int32 extent, char *rid, int32 number, int32 *begin, int32 *output_extent)\r
+{\r
+ int32 ridx_len;\r
+ int32 i,j;\r
+ void *ridx;\r
+ if (blorb_get_chunk(blorb_file, extent,"RIdx",&i,&ridx_len)==NO_REPLY_RV)\r
+  return NO_REPLY_RV;\r
+\r
+ ridx=(char *)blorb_file+i+4;\r
+ ridx_len=read_int((char *)blorb_file+i);\r
+ for(i=0;i<ridx_len;i++)\r
+ { \r
+  if(memcmp((char *)ridx+(i*12),rid,4)==0 && read_int((char *)ridx+(i*12)+4)==number)\r
+  {\r
+   j=i;\r
+   i=read_int((char *)ridx+(j*12)+8);\r
+   *begin=i+8;\r
+   *output_extent=read_int((char *)blorb_file+i+4);\r
+   return 1;\r
+  }\r
+ }\r
+ return NO_REPLY_RV;\r
+}\r
+static int32 blorb_get_story_file(void *blorb_file, int32 extent, int32 *begin, int32 *output_extent)\r
+{\r
+ return blorb_get_resource(blorb_file, extent, "Exec", 0, begin, output_extent);\r
+\r
+}\r
+\r
+static int32 get_story_extent(void *blorb_file, int32 extent)\r
+{\r
+ int32 i,j;\r
+ if (blorb_get_resource(blorb_file, extent, "Exec", 0, &i, &j))\r
+ {\r
+  return j;\r
+ }\r
+ return NO_REPLY_RV;\r
+\r
+}\r
+static int32 get_story_file(void *blorb_file, int32 extent, void *output, int32 output_extent)\r
+{\r
+ int32 i,j;\r
+ if (blorb_get_resource(blorb_file, extent, "Exec", 0, &i, &j))\r
+ {\r
+  ASSERT_OUTPUT_SIZE(j);\r
+  memcpy(output,(char *)blorb_file+i,j);\r
+  return j;\r
+ }\r
+ return NO_REPLY_RV;\r
+\r
+}\r
+\r
+char *blorb_chunk_for_name(char *name)\r
+{\r
+ static char buffer[5];\r
+ int j;\r
+ for(j=0;TranslateExec[j];j+=2)\r
+  if (strcmp(name,TranslateExec[j+1])==0) return TranslateExec[j];\r
+ for(j=0;j<4 && name[j];j++) buffer[j]=toupper(buffer[j]);\r
+ while(j<4) buffer[j++]=' ';\r
+ buffer[4]=0;\r
+ return buffer;\r
+\r
+}\r
+static char *blorb_get_story_format(void *blorb_file, int32 extent)\r
+{\r
+ int32 i, j;\r
+\r
+ for(j=0;treaty_registry[j];j++)\r
+ {\r
+  static char fn[512];\r
+  treaty_registry[j](GET_FORMAT_NAME_SEL,NULL,0,fn,512);\r
+  if (blorb_get_chunk(blorb_file,extent,blorb_chunk_for_name(fn),&i, &i)) return fn;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+static int32 get_story_format(void *blorb_file, int32 extent, char *output, int32 output_extent)\r
+{\r
+ char *o;\r
+ o=blorb_get_story_format(blorb_file, extent);\r
+ if (!o) return NO_REPLY_RV;\r
+ ASSERT_OUTPUT_SIZE((signed) strlen(o)+1);\r
+ strcpy(output,o);\r
+ return strlen(o)+1;\r
+}\r
+static int32 get_story_file_metadata_extent(void *blorb_file, int32 extent)\r
+{\r
+ int32 i,j;\r
+ if (blorb_get_chunk(blorb_file,extent,"IFmd",&i,&j)) return j+1;\r
+ return NO_REPLY_RV;\r
+}\r
+static int32 blorb_get_cover(void *blorb_file, int32 extent, int32 *begin, int32 *output_extent)\r
+{\r
+ int i,j;\r
+ if (blorb_get_chunk(blorb_file,extent,"Fspc",&i,&j))\r
+ {\r
+  if (j<4) return NO_REPLY_RV;\r
+  i=read_int((char *)blorb_file+i);\r
+  if (!blorb_get_resource(blorb_file,extent,"Pict",i,&i,&j)) return NO_REPLY_RV;\r
+  *begin=i;\r
+  *output_extent=j;\r
+  if (memcmp((char *)blorb_file+i-8,"PNG ",4)==0) return PNG_COVER_FORMAT;\r
+  else if (memcmp((char *)blorb_file+i-8,"JPEG",4)==0) return JPEG_COVER_FORMAT;\r
+ }\r
+ return NO_REPLY_RV;\r
+\r
+}\r
+\r
+static int32 get_story_file_cover_extent(void *blorb_file, int32 extent)\r
+{\r
+ int32 i,j;\r
+ if (blorb_get_cover(blorb_file,extent,&i,&j)) return j;\r
+ return NO_REPLY_RV;\r
+}\r
+\r
+static int32 get_story_file_cover_format(void *blorb_file, int32 extent)\r
+{\r
+ int32 i,j;\r
+ return blorb_get_cover(blorb_file, extent, &i,&j);\r
+}\r
+\r
+static int32 get_story_file_IFID(void *b, int32 e, char *output, int32 output_extent)\r
+{\r
+ int32 j;\r
+ char *md;\r
+ j=get_story_file_metadata_extent(b,e);\r
+ if (j<=0) return NO_REPLY_RV;\r
+ md=(char *)my_malloc(j, "Metadata buffer");\r
+ j=get_story_file_metadata(b,e,md,j);\r
+ if (j<=0) return NO_REPLY_RV;\r
+\r
+ j=ifiction_get_IFID(md,output,output_extent);\r
+ free(md);\r
+ return j;\r
+}\r
+\r
+static int32 get_story_file_metadata(void *blorb_file, int32 extent, char *output, int32 output_extent)\r
+{\r
+ int32 i,j;\r
+ if (!blorb_get_chunk(blorb_file, extent,"IFmd",&i,&j)) return NO_REPLY_RV;\r
+ ASSERT_OUTPUT_SIZE(j+1);\r
+ memcpy(output,(char *)blorb_file+i,j);\r
+ output[j]=0;\r
+ return j+1;\r
+}\r
+static int32 get_story_file_cover(void *blorb_file, int32 extent, void *output, int32 output_extent)\r
+{\r
+ int32 i,j;\r
+ if (!blorb_get_cover(blorb_file, extent,&i,&j)) return NO_REPLY_RV;\r
+ ASSERT_OUTPUT_SIZE(j);\r
+ memcpy(output,(char *)blorb_file+i,j);\r
+ return j;\r
+}\r
+\r
+static int32 claim_story_file(void *story_file, int32 extent)\r
+{\r
+ int i;\r
+\r
+ if (extent<16 ||\r
+     memcmp(story_file,"FORM",4) ||\r
+     memcmp((char *)story_file+8,"IFRS",4) \r
+    ) i= INVALID_STORY_FILE_RV;\r
+ else i= NO_REPLY_RV;\r
\r
+ return i;\r
+\r
+}\r