Merge branch 'master' into browser
[projects/chimara/chimara.git] / babel / babel_multi_functions.c
diff --git a/babel/babel_multi_functions.c b/babel/babel_multi_functions.c
new file mode 100644 (file)
index 0000000..cd867c6
--- /dev/null
@@ -0,0 +1,312 @@
+#include "babel.h"\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+int chdir(const char *);\r
+char *getcwd(char *, int);\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+void deep_ifiction_verify(char *md, int f);\r
+void * my_malloc(int32, char *);\r
+char *blorb_chunk_for_name(char *name);\r
+#ifndef THREE_LETTER_EXTENSIONS\r
+static char *ext_table[] = { "zcode", ".zblorb",\r
+                             "glulx", ".gblorb",\r
+                             NULL, NULL\r
+                             };\r
+#else\r
+static char *ext_table[] = { "zcode", ".zlb",\r
+                             "glulx", ".glb",\r
+                             NULL, NULL\r
+                             };\r
+\r
+#endif\r
+char *blorb_ext_for_name(char *fmt)\r
+{\r
+ int i;\r
+ for(i=0;ext_table[i];i+=2)\r
+  if (strcmp(ext_table[i],fmt)==0) return ext_table[i+1];\r
+#ifndef THREE_LETTER_EXTENSIONS\r
+ return ".blorb";\r
+#else\r
+ return ".blb";\r
+#endif\r
+}\r
+\r
+char *deep_complete_ifiction(char *fn, char *ifid, char *format)\r
+{\r
+ FILE *f;\r
+ int32 i;\r
+ char *md;\r
+ char *id, *idp;\r
+ char *idb;\r
+ f=fopen(fn,"r");\r
+ if (!f) { fprintf(stderr,"Error: Can not open file %s\n",fn);\r
+          return NULL;\r
+          }\r
+ fseek(f,0,SEEK_END);\r
+ i=ftell(f);\r
+ fseek(f,0,SEEK_SET);\r
+ md=(char *) my_malloc(i+1,"Metadata buffer");\r
+ fread(md,1,i,f);\r
+ md[i]=0;\r
+ id=strstr(md,"</ifindex>");\r
+ if (id) *(id+10)=0;\r
+ fclose(f);\r
+ id=strdup(ifid);\r
+ idp=strtok(id,",");\r
+ /* Find the identification chunk */\r
+ {\r
+   char *bp, *ep;\r
+   bp=strstr(md,"<identification>");\r
+   if (!bp)\r
+   {\r
+    idb=(char *)my_malloc(TREATY_MINIMUM_EXTENT+128,"ident buffer");\r
+    sprintf(idb,"<format>%s</format>\n", format);\r
+   }\r
+   else\r
+   {\r
+    int ii;\r
+    ep=strstr(bp,"</identification>");\r
+    idb=(char *)my_malloc(TREATY_MINIMUM_EXTENT+128+(ep-bp),"ident buffer");\r
+    for(ii=16;bp+ii<ep;ii++)\r
+    idb[ii-16]=bp[ii];\r
+    idb[ii]=0;\r
+    for(ep+=18;*ep;ep++)\r
+     *bp++=*ep;\r
+    *bp=0;\r
+    bp=strstr(idb,"<format>");\r
+    if (bp)\r
+     if (memcmp(bp+8,format,strlen(format)))\r
+      fprintf(stderr,"Error: Format in sparse .iFiction does not match story\n");\r
+\r
+   }\r
+\r
+ }\r
+ /* Insert the new ifids */\r
+ while(idp)\r
+ {\r
+  char bfr[TREATY_MINIMUM_EXTENT];\r
+  sprintf(bfr,"<ifid>%s</ifid>",idp);\r
+  if (!strstr(idb,bfr)) { strcat(idb,bfr); strcat(idb,"\n"); }\r
+  idp=strtok(NULL,",");\r
+\r
+ }\r
+ free(id);\r
+ idp=(char *) my_malloc(strlen(md)+strlen(idb)+64, "Output metadata");\r
+/* printf("%d bytes for metadata\n",strlen(md)+strlen(idb)+64);*/\r
+ id=strstr(md,"<story>");\r
+ id[0]=0;\r
+ id+=7;\r
+ strcpy(idp,md);\r
+ strcat(idp,"<story>\n <identification>\n");\r
+ strcat(idp,idb);\r
+ free(idb);\r
+ strcat(idp," </identification>\n");\r
+ strcat(idp,id);\r
+ free(md);\r
+ md=idp;\r
+ deep_ifiction_verify(md, 0);\r
+ return md;\r
+}\r
+\r
+void write_int(int32 i, FILE *f)\r
+{\r
+ char bf[4];\r
+ bf[0]=(((unsigned) i) >> 24) & 0xFF;\r
+ bf[1]=(((unsigned) i) >> 16) & 0xFF;\r
+ bf[2]=(((unsigned) i) >> 8) & 0xFF;\r
+ bf[3]=(((unsigned) i)) & 0xFF;\r
+ fwrite(bf,1,4,f);\r
+}\r
+static void _babel_multi_blorb(char *outfile, char **args, char *todir , int argc)\r
+{\r
+ int32 total, storyl, coverl, i;\r
+ char buffer[TREATY_MINIMUM_EXTENT+10];\r
+ char b2[TREATY_MINIMUM_EXTENT];\r
+\r
+ char cwd[512];\r
+ char *cover, *md, *cvrf, *ep;\r
+\r
+ FILE *f, *c;\r
+ if (argc!=2 && argc !=3)\r
+ {\r
+  fprintf(stderr,"Invalid usage\n");\r
+  return;\r
+ }\r
+ if (!babel_init(args[0]))\r
+ {\r
+  fprintf(stderr,"Error: Could not determine the format of file %s\n",args[0]);\r
+  return;\r
+ }\r
+ if (babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT)<=0 ||\r
+     babel_treaty(GET_FORMAT_NAME_SEL,b2,TREATY_MINIMUM_EXTENT)<0\r
+    )\r
+ {\r
+  fprintf(stderr,"Error: Could not deduce an IFID for file %s\n",args[0]);\r
+  return;\r
+ }\r
+ if (babel_get_length() != babel_get_story_length())\r
+ {\r
+  fprintf(stderr,"Warning: Story file will be extacted from container before blorbing\n");\r
+ }\r
+/* printf("Completing ifiction\n");*/\r
+ md=deep_complete_ifiction(args[1],buffer,b2);\r
+/* printf("Ifiction is %d bytes long\n",strlen(md));*/\r
+ ep=strchr(buffer,',');\r
+ if (ep) *ep=0;\r
+ if (outfile)\r
+  strcpy(buffer,outfile);\r
+ strcat(buffer,blorb_ext_for_name(b2));\r
+ getcwd(cwd,512);\r
+ chdir(todir);\r
+ f=fopen(buffer,"wb");\r
+ chdir(cwd);\r
+ if (!f)\r
+ {\r
+  fprintf(stderr,"Error: Error writing to file %s\n",buffer);\r
+  return;\r
+ }\r
+ storyl=babel_get_story_length();\r
+ total=storyl + (storyl%2) + 36;\r
+ if (md) total+=8+strlen(md)+strlen(md)%2;\r
+ if (argc==3)\r
+ {\r
+  c=fopen(args[2],"rb");\r
+  if (c)\r
+  {\r
+   fseek(c,0,SEEK_END);\r
+   coverl=ftell(c);\r
+   if (coverl > 5){\r
+\r
+   cover=(char *) my_malloc(coverl+2,"Cover art buffer");\r
+   fseek(c,0,SEEK_SET);\r
+   fread(cover,1,coverl,c);\r
+   if (memcmp(cover+1,"PNG",3)==0) cvrf="PNG ";\r
+   else cvrf="JPEG";\r
+   total += 32+coverl + (coverl%2);\r
+   }\r
+   else argc=2;\r
+   fclose(c);\r
+  }\r
+  else argc=2;\r
+ }\r
+/* printf("Writing header\n;");*/\r
+ fwrite("FORM",1,4,f);\r
+ write_int(total,f);\r
+/* printf("Writing index\n;");*/\r
+ fwrite("IFRSRIdx",1,8,f);\r
+ write_int(argc==3 ? 28:16,f);\r
+ write_int(argc==3 ? 2:1,f);\r
+/* printf("Writing story\n;");*/\r
+ fwrite("Exec", 1,4,f);\r
+ write_int(0,f);\r
+ write_int(argc==3 ? 48:36,f);\r
+ if (argc==3)\r
+ {\r
+/* printf("Writing image\n;"); */\r
+ fwrite("Pict", 1,4,f);\r
+ write_int(1,f);\r
+ write_int(56+storyl+(storyl%2),f);\r
+ }\r
+/* printf("Invoking chunk for name %s\n",b2); */\r
+ fwrite(blorb_chunk_for_name(b2),1,4,f);\r
+ write_int(storyl,f);\r
+/* printf("Writing story data\n"); */\r
+ fwrite(babel_get_story_file(),1,storyl,f);\r
+ if (storyl%2) fwrite("\0",1,1,f);\r
+ if (argc==3)\r
+ {\r
+/*  printf("Writing cover data header %s\n",cvrf); */\r
+  fwrite(cvrf,1,4,f);\r
+/*  printf("Writing cover data size %d\n",coverl); */\r
+  write_int(coverl,f);\r
+/*  printf("Writing cover data\n"); */\r
+  fwrite(cover,1,coverl,f);\r
+  if (coverl%2) fwrite("\0",1,1,f);\r
+/*  printf("Done with cover\n");*/\r
+/*  free(cover);*/\r
+/*  printf("Writing frontispiece\n;");*/\r
+  fwrite("Fspc\0\0\0\004\0\0\0\001",1,12,f);\r
+ }\r
+\r
+ if (md) {\r
+/*  printf("Writing metadata\n;");*/\r
+ fwrite("IFmd",1,4,f);\r
+ write_int(strlen(md),f);\r
+ fwrite(md,1,strlen(md),f);\r
+ if (strlen(md)%2)\r
+  fwrite("\0",1,1,f);\r
+ free(md);\r
+ }\r
+\r
+ fclose(f);\r
+ printf("Created %s\n",buffer);\r
\r
+}\r
+void babel_multi_complete(char **args, char *todir, int argc)\r
+{\r
+ char buffer[TREATY_MINIMUM_EXTENT+10];\r
+  char b2[TREATY_MINIMUM_EXTENT];\r
+ char cwd[512];\r
+ char *ep, *md;\r
+ FILE *f;\r
+ if (argc!=2)\r
+ {\r
+  fprintf(stderr,"Invalid usage\n");\r
+  return;\r
+ }\r
+ if (!babel_init(args[0]))\r
+ {\r
+  fprintf(stderr,"Error: Could not determine the format of file %s\n",args[0]);\r
+  return;\r
+ }\r
+ if (babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT)<=0\r
+    ||  babel_treaty(GET_FORMAT_NAME_SEL,b2,TREATY_MINIMUM_EXTENT)<0)\r
+ {\r
+  fprintf(stderr,"Error: Could not deduce an IFID for file %s\n",args[0]);\r
+  return;\r
+ }\r
+ md=deep_complete_ifiction(args[1],buffer, b2);\r
+ if (!md) return;\r
+ ep=strchr(buffer,',');\r
+ if (ep) *ep=0;\r
+ strcat(buffer,".iFiction");\r
+ getcwd(cwd,512);\r
+ chdir(todir);\r
+ f=fopen(buffer,"w");\r
+ chdir(cwd);\r
+ if (!f || !fputs(md,f))\r
+ {\r
+  fprintf(stderr,"Error: Error writing to file %s\n",buffer);\r
+  return;\r
+ }\r
+ fclose(f);\r
+ free(md);\r
+ printf("Created %s\n",buffer);\r
+}\r
+void babel_multi_blorb(char **args, char *todir , int argc)\r
+{\r
+ _babel_multi_blorb(NULL,args,todir,argc);\r
+}\r
+void babel_multi_blorb1(char **args, char *todir , int argc)\r
+{\r
+ char *buf;\r
+ char *bb;\r
+ buf=(char *)my_malloc(strlen(args[0])+1,"blorb name buffer");\r
+ strcpy(buf,args[0]);\r
+ bb=strrchr(buf,'.');\r
+ if (bb) *bb=0;\r
+ _babel_multi_blorb(buf,args,todir,argc);\r
+ free(buf);\r
\r
+\r
+}\r