Merge branch 'master' into browser
[projects/chimara/chimara.git] / babel / babel_story_functions.c
diff --git a/babel/babel_story_functions.c b/babel/babel_story_functions.c
new file mode 100644 (file)
index 0000000..b1cf0e9
--- /dev/null
@@ -0,0 +1,411 @@
+/* babel_story_functions.c babel top-level operations for story files\r
+ * (c) 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 babel_handler.c, babel.h, and misc.c\r
+ */\r
+\r
+#include "babel.h"\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#ifndef THREE_LETTER_EXTENSIONS\r
+#define IFICTION_EXT ".iFiction"\r
+#else\r
+#define IFICTION_EXT ".ifi"\r
+#endif\r
+void *my_malloc(int32, char *);\r
+\r
+void babel_story_ifid()\r
+{\r
+  char buffer[TREATY_MINIMUM_EXTENT];\r
+  char *ep;\r
+  int i;\r
+  i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
+  ep=strtok(buffer, ",");\r
+  while(ep)\r
+  {\r
+   printf("IFID: %s\n",ep);\r
+   ep=strtok(NULL,",");\r
+  }\r
+  if (!i)\r
+    fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
+\r
+}\r
+\r
+\r
+void babel_story_format()\r
+{\r
+  char *b;\r
+  b=babel_get_format();\r
+  if (!b) b="unknown";\r
+  if (!babel_get_authoritative())\r
+   printf("Format: %s (non-authoritative)\n",b);   \r
+  else printf("Format: %s\n",b);\r
+}\r
+\r
+static void deep_babel_ifiction(char stopped)\r
+{\r
+  char buffer[TREATY_MINIMUM_EXTENT];\r
+  char *md;\r
+  char *ep;\r
+  int32 i;\r
+  FILE *f;\r
+\r
+  if (stopped!=2)\r
+  {\r
+  i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
+  if (i==0 && !babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
+  {\r
+   fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
+   return;\r
+  }\r
+\r
+\r
+  ep=strtok(buffer, ",");\r
+  }\r
+  else ep="-";\r
+  i=babel_treaty(GET_STORY_FILE_METADATA_EXTENT_SEL,NULL,0);\r
+  if (i<=0)\r
+  {\r
+   if (stopped) printf("No iFiction record for %s\n",buffer);\r
+   return;\r
+  }\r
+  md=(char *)my_malloc(i,"Metadata buffer");\r
+  if (babel_treaty(GET_STORY_FILE_METADATA_SEL,md,i)<0)\r
+  {\r
+    fprintf(stderr,"A serious error occurred while retrieving metadata.\n");\r
+    free(md);\r
+    return;\r
+  }\r
+  while(ep)\r
+  {\r
+   char epb[TREATY_MINIMUM_EXTENT+9];\r
+   if (stopped!=2)\r
+   {\r
+   strcpy(epb,ep);\r
+   strcat(epb, IFICTION_EXT);\r
+\r
+   f=fopen(epb,"w");\r
+   }\r
+   else f=stdout;\r
+\r
+   if (!f || fputs(md,f)==EOF)\r
+    fprintf(stderr,"A serious error occurred writing to disk.\n");\r
+   else if (stopped!=2) printf("Extracted %s\n",epb);\r
+   if (f) fclose(f);\r
+   if (stopped) break;\r
+   ep=strtok(NULL,",");\r
+  }\r
+  free(md);\r
+}\r
+\r
+void babel_story_ifiction()\r
+{\r
+ deep_babel_ifiction(1);\r
+}\r
+static char *get_jpeg_dim(void *img, int32 extent)\r
+{\r
+  unsigned char *dp=(unsigned char *) img;\r
+  unsigned char *ep=dp+extent;\r
+  static char buffer[256];\r
+  unsigned int t1, t2, w, h;\r
+\r
+\r
+  t1=*(dp++);\r
+  t2=*(dp++);\r
+  if (t1!=0xff || t2!=0xD8 )\r
+  {\r
+   return "(invalid)";\r
+  }\r
+\r
+  while(1)\r
+  {\r
+   if (dp>ep) return "(invalid)";\r
+   for(t1=*(dp++);t1!=0xff;t1=*(dp++)) if (dp>ep) return "(invalid)";\r
+   do { t1=*(dp++); if (dp>ep) return "(invalid 4)";} while (t1 == 0xff);\r
+\r
+   if ((t1 & 0xF0) == 0xC0 && !(t1==0xC4 || t1==0xC8 || t1==0xCC))\r
+   {\r
+    dp+=3;\r
+    if (dp>ep) return "(invalid)";\r
+    h=*(dp++) << 8;\r
+    if (dp>ep) return "(invalid)";\r
+    h|=*(dp++);\r
+    if (dp>ep) return "(invalid)";\r
+    w=*(dp++) << 8;\r
+    if (dp>ep) return "(invalid)";\r
+    w|=*(dp);\r
+    sprintf(buffer, "(%dx%d)",w,h);\r
+    return buffer;\r
+   }\r
+   else if (t1==0xD8 || t1==0xD9)\r
+    break;\r
+   else\r
+   { int l;\r
+\r
+    if (dp>ep) return "(invalid)";\r
+     l=*(dp++) << 8;\r
+    if (dp>ep) return "(invalid)";\r
+     l|= *(dp++);\r
+     l-=2;\r
+     dp+=l;\r
+     if (dp>ep) return "(invalid)";\r
+    }\r
+   }\r
+  return "(invalid)";\r
+}\r
+\r
+static int32 read_int(unsigned char  *mem)\r
+{\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 char *get_png_dim(void *img, int32 extent)\r
+{\r
+ unsigned char *dp=(unsigned char *)img;\r
+ static char buffer[256];\r
+ int32 w, h;\r
+ if (extent<33 ||\r
+ !(dp[0]==137 && dp[1]==80 && dp[2]==78 && dp[3]==71 &&\r
+        dp[4]==13 && dp[5] == 10 && dp[6] == 26 && dp[7]==10)||\r
+ !(dp[12]=='I' && dp[13]=='H' && dp[14]=='D' && dp[15]=='R'))\r
+ return "(invalid)";\r
+ w=read_int(dp+16);\r
+ h=read_int(dp+20);\r
+ sprintf(buffer,"(%dx%d)",w,h);\r
+ return buffer;\r
+}\r
+static char *get_image_dim(void *img, int32 extent, int fmt)\r
+{\r
+ if (fmt==JPEG_COVER_FORMAT) return get_jpeg_dim(img,extent);\r
+ else if (fmt==PNG_COVER_FORMAT) return get_png_dim(img, extent);\r
+ return "(unknown)";\r
+\r
+}\r
+static void deep_babel_cover(char stopped)\r
+{\r
+  char buffer[TREATY_MINIMUM_EXTENT];\r
+  void *md;\r
+  char *ep;\r
+  char *ext;\r
+  char *dim;\r
+  int32 i,j;\r
+  FILE *f;\r
+  i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
+  if (i==0)\r
+   if (babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
+    printf("IFID: %s\n",buffer);\r
+   else\r
+    {\r
+     fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
+     return;\r
+    }\r
+  else \r
+\r
+  ep=strtok(buffer, ",");\r
+  i=babel_treaty(GET_STORY_FILE_COVER_EXTENT_SEL,NULL,0);\r
+  j=babel_treaty(GET_STORY_FILE_COVER_FORMAT_SEL,NULL,0);\r
+\r
+  if (i<=0 || j<=0)\r
+  {\r
+   if (stopped) printf("No cover art for %s\n",buffer);\r
+   return;\r
+  }\r
+  if (j==PNG_COVER_FORMAT) ext=".png";\r
+  else if (j==JPEG_COVER_FORMAT) ext=".jpg";\r
+  md=my_malloc(i,"Image buffer");\r
+  if (babel_treaty(GET_STORY_FILE_COVER_SEL,md,i)<0)\r
+  {\r
+    fprintf(stderr,"A serious error occurred while retrieving cover art.\n");\r
+    free(md);\r
+    return;\r
+  }\r
+  dim=get_image_dim(md,i,j);\r
+  while(ep)\r
+  {\r
+   char epb[TREATY_MINIMUM_EXTENT+9];\r
+   strcpy(epb,ep);\r
+   strcat(epb, ext);\r
+\r
+   f=fopen(epb,"wb");\r
+   if (!f || fwrite(md,1,i,f)==EOF)\r
+    fprintf(stderr,"A serious error occurred writing to disk.\n");\r
+   else printf("Extracted %s %s\n",epb, dim);\r
+   if (f) fclose(f);\r
+   if (stopped) break;\r
+   ep=strtok(NULL,",");\r
+  }\r
+  free(md);\r
+}\r
+\r
+void babel_story_cover()\r
+{\r
+ deep_babel_cover(1);\r
+}\r
+\r
+void babel_story_fish()\r
+{\r
+ deep_babel_ifiction(0);\r
+ deep_babel_cover(0);\r
+}\r
+\r
+static char *get_biblio(void)\r
+{\r
+ int32 i;\r
+ char *md;\r
+ char *bib="No bibliographic data";\r
+ char *bibb; char *bibe; \r
+ char *t;\r
+ static char buffer[TREATY_MINIMUM_EXTENT];\r
+\r
+ i=babel_treaty(GET_STORY_FILE_METADATA_EXTENT_SEL,NULL,0);\r
+ if (i<=0) return bib;\r
+\r
+ md=(char *) my_malloc(i,"Metadata buffer");\r
+ if (babel_treaty(GET_STORY_FILE_METADATA_SEL,md,i)<0) return bib;\r
\r
+ bibb=strstr(md,"<bibliographic>");\r
+ if (!bibb) { free(md); return bib; }\r
+ bibe=strstr(bibb,"</bibliographic>");\r
+ if (bibe) *bibe=0;\r
+ t=strstr(bibb,"<title>");\r
+ if (t)\r
+ {\r
+  t+=7;\r
+  bibe=strstr(t,"</title>");\r
+  if (bibe)\r
+  {\r
+    *bibe=0;\r
+    bib=buffer;\r
+    for(i=0;t[i];i++) if (t[i]<0x20 || t[i]>0x7e) t[i]='_';\r
+    sprintf(buffer, "\"%s\" ",t);\r
+    *bibe='<';\r
+  }\r
+  else strcpy(buffer,"<no title found> ");\r
+ }\r
+ t=strstr(bibb,"<author>");\r
+ if (t)\r
+ {\r
+  t+=8;\r
+  bibe=strstr(t,"</author>");\r
+  if (bibe)\r
+  {\r
+    bib=buffer;\r
+    *bibe=0;\r
+    for(i=0;t[i];i++) if (t[i]<0x20 || t[i]>0x7e) t[i]='_';\r
+    strcat(buffer, "by ");\r
+    strcat(buffer, t);\r
+    *bibe='<';\r
+  }\r
+  else strcat(buffer, "<no author found>");\r
+ }\r
+ free(md);\r
+ return bib;\r
+\r
+}\r
+void babel_story_identify()\r
+{\r
+ int32 i, j, l;\r
+ char *b, *cf, *dim;\r
+ char buffer[TREATY_MINIMUM_EXTENT];\r
+\r
+ printf("%s\n",get_biblio());\r
+ babel_story_ifid();\r
+ b=babel_get_format();\r
+ if (!b) b="unknown";\r
+ l=babel_get_length() / 1024;\r
\r
+\r
+ i=babel_treaty(GET_STORY_FILE_COVER_EXTENT_SEL,NULL,0);\r
+ j=babel_treaty(GET_STORY_FILE_COVER_FORMAT_SEL,NULL,0);\r
+\r
+ if (i<=0 || j<=0)\r
+ {\r
+  cf="no cover"; \r
+ }\r
+ else\r
+ {\r
+  char *md=my_malloc(i,"Image buffer");\r
+  if (babel_treaty(GET_STORY_FILE_COVER_SEL,md,i)<0)\r
+  {\r
+   cf="no cover";\r
+  }\r
+  else\r
+  {\r
+   dim=get_image_dim(md,i,j)+1;\r
+   dim[strlen(dim)-1]=0;\r
+   if (j==JPEG_COVER_FORMAT) cf="jpeg";\r
+   else if (j==PNG_COVER_FORMAT) cf="png";\r
+   else cf="unknown format";\r
+   sprintf(buffer,"cover %s %s",dim,cf);\r
+   cf=buffer;\r
+  }\r
+ }\r
+ printf("%s, %dk, %s\n",b, l,cf);\r
+}\r
+\r
+void babel_story_meta()\r
+{\r
+ deep_babel_ifiction(2);\r
+}\r
+\r
+void babel_story_story()\r
+{\r
+  int32 j,i;\r
+  void *p;\r
+  FILE *f;\r
+  char *ep;\r
+  char buffer[TREATY_MINIMUM_EXTENT+20];\r
+  j=babel_get_story_length();\r
+  p=babel_get_story_file();\r
+  if (!j || !p)\r
+  {\r
+    fprintf(stderr,"A serious error occurred while retrieving the story file.\n");\r
+    return;\r
+  }\r
+\r
+  i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
+  if (i==0 && !babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
+  {\r
+   fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
+   return;\r
+  }\r
+  ep=strchr(buffer, ',');\r
+  if (!ep) ep=buffer+strlen(buffer);\r
+  *ep=0;\r
+  babel_treaty(GET_STORY_FILE_EXTENSION_SEL,ep,19);\r
+  f=fopen(buffer,"wb");\r
+  if (!f || !fwrite(p,1,j,f))\r
+    {\r
+     fprintf(stderr,"A serious error occurred writing to disk.\n");\r
+     return;\r
+    }\r
+ fclose(f);\r
+ printf("Extracted %s\n",buffer);\r
+\r
+  \r
+\r
+}\r
+\r
+void babel_story_unblorb()\r
+{\r
+ deep_babel_ifiction(1);\r
+ deep_babel_cover(1);\r
+ babel_story_story();\r
+\r
+}\r