b1cf0e9963025d0a3aa259ab4a2aba2c55ec1107
[projects/chimara/chimara.git] / babel / babel_story_functions.c
1 /* babel_story_functions.c babel top-level operations for story files\r
2  * (c) 2006 By L. Ross Raszewski\r
3  *\r
4  * This code is freely usable for all purposes.\r
5  *\r
6  * This work is licensed under the Creative Commons Attribution2.5 License.\r
7  * To view a copy of this license, visit\r
8  * http://creativecommons.org/licenses/by/2.5/ or send a letter to\r
9  * Creative Commons,\r
10  * 543 Howard Street, 5th Floor,\r
11  * San Francisco, California, 94105, USA.\r
12  *\r
13  * This file depends upon babel_handler.c, babel.h, and misc.c\r
14  */\r
15 \r
16 #include "babel.h"\r
17 #include <stdio.h>\r
18 #include <stdlib.h>\r
19 #include <string.h>\r
20 \r
21 #ifndef THREE_LETTER_EXTENSIONS\r
22 #define IFICTION_EXT ".iFiction"\r
23 #else\r
24 #define IFICTION_EXT ".ifi"\r
25 #endif\r
26 void *my_malloc(int32, char *);\r
27 \r
28 void babel_story_ifid()\r
29 {\r
30   char buffer[TREATY_MINIMUM_EXTENT];\r
31   char *ep;\r
32   int i;\r
33   i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
34   ep=strtok(buffer, ",");\r
35   while(ep)\r
36   {\r
37    printf("IFID: %s\n",ep);\r
38    ep=strtok(NULL,",");\r
39   }\r
40   if (!i)\r
41     fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
42 \r
43 }\r
44 \r
45 \r
46 void babel_story_format()\r
47 {\r
48   char *b;\r
49   b=babel_get_format();\r
50   if (!b) b="unknown";\r
51   if (!babel_get_authoritative())\r
52    printf("Format: %s (non-authoritative)\n",b);   \r
53   else printf("Format: %s\n",b);\r
54 }\r
55 \r
56 static void deep_babel_ifiction(char stopped)\r
57 {\r
58   char buffer[TREATY_MINIMUM_EXTENT];\r
59   char *md;\r
60   char *ep;\r
61   int32 i;\r
62   FILE *f;\r
63 \r
64   if (stopped!=2)\r
65   {\r
66   i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
67   if (i==0 && !babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
68   {\r
69    fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
70    return;\r
71   }\r
72 \r
73 \r
74   ep=strtok(buffer, ",");\r
75   }\r
76   else ep="-";\r
77   i=babel_treaty(GET_STORY_FILE_METADATA_EXTENT_SEL,NULL,0);\r
78   if (i<=0)\r
79   {\r
80    if (stopped) printf("No iFiction record for %s\n",buffer);\r
81    return;\r
82   }\r
83   md=(char *)my_malloc(i,"Metadata buffer");\r
84   if (babel_treaty(GET_STORY_FILE_METADATA_SEL,md,i)<0)\r
85   {\r
86     fprintf(stderr,"A serious error occurred while retrieving metadata.\n");\r
87     free(md);\r
88     return;\r
89   }\r
90   while(ep)\r
91   {\r
92    char epb[TREATY_MINIMUM_EXTENT+9];\r
93    if (stopped!=2)\r
94    {\r
95    strcpy(epb,ep);\r
96    strcat(epb, IFICTION_EXT);\r
97 \r
98    f=fopen(epb,"w");\r
99    }\r
100    else f=stdout;\r
101 \r
102    if (!f || fputs(md,f)==EOF)\r
103     fprintf(stderr,"A serious error occurred writing to disk.\n");\r
104    else if (stopped!=2) printf("Extracted %s\n",epb);\r
105    if (f) fclose(f);\r
106    if (stopped) break;\r
107    ep=strtok(NULL,",");\r
108   }\r
109   free(md);\r
110 }\r
111 \r
112 void babel_story_ifiction()\r
113 {\r
114  deep_babel_ifiction(1);\r
115 }\r
116 static char *get_jpeg_dim(void *img, int32 extent)\r
117 {\r
118   unsigned char *dp=(unsigned char *) img;\r
119   unsigned char *ep=dp+extent;\r
120   static char buffer[256];\r
121   unsigned int t1, t2, w, h;\r
122 \r
123 \r
124   t1=*(dp++);\r
125   t2=*(dp++);\r
126   if (t1!=0xff || t2!=0xD8 )\r
127   {\r
128    return "(invalid)";\r
129   }\r
130 \r
131   while(1)\r
132   {\r
133    if (dp>ep) return "(invalid)";\r
134    for(t1=*(dp++);t1!=0xff;t1=*(dp++)) if (dp>ep) return "(invalid)";\r
135    do { t1=*(dp++); if (dp>ep) return "(invalid 4)";} while (t1 == 0xff);\r
136 \r
137    if ((t1 & 0xF0) == 0xC0 && !(t1==0xC4 || t1==0xC8 || t1==0xCC))\r
138    {\r
139     dp+=3;\r
140     if (dp>ep) return "(invalid)";\r
141     h=*(dp++) << 8;\r
142     if (dp>ep) return "(invalid)";\r
143     h|=*(dp++);\r
144     if (dp>ep) return "(invalid)";\r
145     w=*(dp++) << 8;\r
146     if (dp>ep) return "(invalid)";\r
147     w|=*(dp);\r
148     sprintf(buffer, "(%dx%d)",w,h);\r
149     return buffer;\r
150    }\r
151    else if (t1==0xD8 || t1==0xD9)\r
152     break;\r
153    else\r
154    { int l;\r
155 \r
156     if (dp>ep) return "(invalid)";\r
157      l=*(dp++) << 8;\r
158     if (dp>ep) return "(invalid)";\r
159      l|= *(dp++);\r
160      l-=2;\r
161      dp+=l;\r
162      if (dp>ep) return "(invalid)";\r
163     }\r
164    }\r
165   return "(invalid)";\r
166 }\r
167 \r
168 static int32 read_int(unsigned char  *mem)\r
169 {\r
170   int32 i4 = mem[0],\r
171                     i3 = mem[1],\r
172                     i2 = mem[2],\r
173                     i1 = mem[3];\r
174   return i1 | (i2<<8) | (i3<<16) | (i4<<24);\r
175 }\r
176 \r
177 \r
178 static char *get_png_dim(void *img, int32 extent)\r
179 {\r
180  unsigned char *dp=(unsigned char *)img;\r
181  static char buffer[256];\r
182  int32 w, h;\r
183  if (extent<33 ||\r
184  !(dp[0]==137 && dp[1]==80 && dp[2]==78 && dp[3]==71 &&\r
185         dp[4]==13 && dp[5] == 10 && dp[6] == 26 && dp[7]==10)||\r
186  !(dp[12]=='I' && dp[13]=='H' && dp[14]=='D' && dp[15]=='R'))\r
187  return "(invalid)";\r
188  w=read_int(dp+16);\r
189  h=read_int(dp+20);\r
190  sprintf(buffer,"(%dx%d)",w,h);\r
191  return buffer;\r
192 }\r
193 static char *get_image_dim(void *img, int32 extent, int fmt)\r
194 {\r
195  if (fmt==JPEG_COVER_FORMAT) return get_jpeg_dim(img,extent);\r
196  else if (fmt==PNG_COVER_FORMAT) return get_png_dim(img, extent);\r
197  return "(unknown)";\r
198 \r
199 }\r
200 static void deep_babel_cover(char stopped)\r
201 {\r
202   char buffer[TREATY_MINIMUM_EXTENT];\r
203   void *md;\r
204   char *ep;\r
205   char *ext;\r
206   char *dim;\r
207   int32 i,j;\r
208   FILE *f;\r
209   i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
210   if (i==0)\r
211    if (babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
212     printf("IFID: %s\n",buffer);\r
213    else\r
214     {\r
215      fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
216      return;\r
217     }\r
218   else \r
219 \r
220   ep=strtok(buffer, ",");\r
221   i=babel_treaty(GET_STORY_FILE_COVER_EXTENT_SEL,NULL,0);\r
222   j=babel_treaty(GET_STORY_FILE_COVER_FORMAT_SEL,NULL,0);\r
223 \r
224   if (i<=0 || j<=0)\r
225   {\r
226    if (stopped) printf("No cover art for %s\n",buffer);\r
227    return;\r
228   }\r
229   if (j==PNG_COVER_FORMAT) ext=".png";\r
230   else if (j==JPEG_COVER_FORMAT) ext=".jpg";\r
231   md=my_malloc(i,"Image buffer");\r
232   if (babel_treaty(GET_STORY_FILE_COVER_SEL,md,i)<0)\r
233   {\r
234     fprintf(stderr,"A serious error occurred while retrieving cover art.\n");\r
235     free(md);\r
236     return;\r
237   }\r
238   dim=get_image_dim(md,i,j);\r
239   while(ep)\r
240   {\r
241    char epb[TREATY_MINIMUM_EXTENT+9];\r
242    strcpy(epb,ep);\r
243    strcat(epb, ext);\r
244 \r
245    f=fopen(epb,"wb");\r
246    if (!f || fwrite(md,1,i,f)==EOF)\r
247     fprintf(stderr,"A serious error occurred writing to disk.\n");\r
248    else printf("Extracted %s %s\n",epb, dim);\r
249    if (f) fclose(f);\r
250    if (stopped) break;\r
251    ep=strtok(NULL,",");\r
252   }\r
253   free(md);\r
254 }\r
255 \r
256 void babel_story_cover()\r
257 {\r
258  deep_babel_cover(1);\r
259 }\r
260 \r
261 void babel_story_fish()\r
262 {\r
263  deep_babel_ifiction(0);\r
264  deep_babel_cover(0);\r
265 }\r
266 \r
267 static char *get_biblio(void)\r
268 {\r
269  int32 i;\r
270  char *md;\r
271  char *bib="No bibliographic data";\r
272  char *bibb; char *bibe; \r
273  char *t;\r
274  static char buffer[TREATY_MINIMUM_EXTENT];\r
275 \r
276  i=babel_treaty(GET_STORY_FILE_METADATA_EXTENT_SEL,NULL,0);\r
277  if (i<=0) return bib;\r
278 \r
279  md=(char *) my_malloc(i,"Metadata buffer");\r
280  if (babel_treaty(GET_STORY_FILE_METADATA_SEL,md,i)<0) return bib;\r
281  \r
282  bibb=strstr(md,"<bibliographic>");\r
283  if (!bibb) { free(md); return bib; }\r
284  bibe=strstr(bibb,"</bibliographic>");\r
285  if (bibe) *bibe=0;\r
286  t=strstr(bibb,"<title>");\r
287  if (t)\r
288  {\r
289   t+=7;\r
290   bibe=strstr(t,"</title>");\r
291   if (bibe)\r
292   {\r
293     *bibe=0;\r
294     bib=buffer;\r
295     for(i=0;t[i];i++) if (t[i]<0x20 || t[i]>0x7e) t[i]='_';\r
296     sprintf(buffer, "\"%s\" ",t);\r
297     *bibe='<';\r
298   }\r
299   else strcpy(buffer,"<no title found> ");\r
300  }\r
301  t=strstr(bibb,"<author>");\r
302  if (t)\r
303  {\r
304   t+=8;\r
305   bibe=strstr(t,"</author>");\r
306   if (bibe)\r
307   {\r
308     bib=buffer;\r
309     *bibe=0;\r
310     for(i=0;t[i];i++) if (t[i]<0x20 || t[i]>0x7e) t[i]='_';\r
311     strcat(buffer, "by ");\r
312     strcat(buffer, t);\r
313     *bibe='<';\r
314   }\r
315   else strcat(buffer, "<no author found>");\r
316  }\r
317  free(md);\r
318  return bib;\r
319 \r
320 }\r
321 void babel_story_identify()\r
322 {\r
323  int32 i, j, l;\r
324  char *b, *cf, *dim;\r
325  char buffer[TREATY_MINIMUM_EXTENT];\r
326 \r
327  printf("%s\n",get_biblio());\r
328  babel_story_ifid();\r
329  b=babel_get_format();\r
330  if (!b) b="unknown";\r
331  l=babel_get_length() / 1024;\r
332  \r
333 \r
334  i=babel_treaty(GET_STORY_FILE_COVER_EXTENT_SEL,NULL,0);\r
335  j=babel_treaty(GET_STORY_FILE_COVER_FORMAT_SEL,NULL,0);\r
336 \r
337  if (i<=0 || j<=0)\r
338  {\r
339   cf="no cover"; \r
340  }\r
341  else\r
342  {\r
343   char *md=my_malloc(i,"Image buffer");\r
344   if (babel_treaty(GET_STORY_FILE_COVER_SEL,md,i)<0)\r
345   {\r
346    cf="no cover";\r
347   }\r
348   else\r
349   {\r
350    dim=get_image_dim(md,i,j)+1;\r
351    dim[strlen(dim)-1]=0;\r
352    if (j==JPEG_COVER_FORMAT) cf="jpeg";\r
353    else if (j==PNG_COVER_FORMAT) cf="png";\r
354    else cf="unknown format";\r
355    sprintf(buffer,"cover %s %s",dim,cf);\r
356    cf=buffer;\r
357   }\r
358  }\r
359  printf("%s, %dk, %s\n",b, l,cf);\r
360 }\r
361 \r
362 void babel_story_meta()\r
363 {\r
364  deep_babel_ifiction(2);\r
365 }\r
366 \r
367 void babel_story_story()\r
368 {\r
369   int32 j,i;\r
370   void *p;\r
371   FILE *f;\r
372   char *ep;\r
373   char buffer[TREATY_MINIMUM_EXTENT+20];\r
374   j=babel_get_story_length();\r
375   p=babel_get_story_file();\r
376   if (!j || !p)\r
377   {\r
378     fprintf(stderr,"A serious error occurred while retrieving the story file.\n");\r
379     return;\r
380   }\r
381 \r
382   i=babel_treaty(GET_STORY_FILE_IFID_SEL,buffer,TREATY_MINIMUM_EXTENT);\r
383   if (i==0 && !babel_md5_ifid(buffer, TREATY_MINIMUM_EXTENT))\r
384   {\r
385    fprintf(stderr,"Unable to create an IFID (A serious problem occurred while loading the file).\n");\r
386    return;\r
387   }\r
388   ep=strchr(buffer, ',');\r
389   if (!ep) ep=buffer+strlen(buffer);\r
390   *ep=0;\r
391   babel_treaty(GET_STORY_FILE_EXTENSION_SEL,ep,19);\r
392   f=fopen(buffer,"wb");\r
393   if (!f || !fwrite(p,1,j,f))\r
394     {\r
395      fprintf(stderr,"A serious error occurred writing to disk.\n");\r
396      return;\r
397     }\r
398  fclose(f);\r
399  printf("Extracted %s\n",buffer);\r
400 \r
401   \r
402 \r
403 }\r
404 \r
405 void babel_story_unblorb()\r
406 {\r
407  deep_babel_ifiction(1);\r
408  deep_babel_cover(1);\r
409  babel_story_story();\r
410 \r
411 }\r