ebb84e4ba31806995316ba31ebed7aa07027a811
[projects/chimara/chimara.git] / babel / blorb.c
1 /* blorb.c      Babel interface to blorb files\r
2  * Copyright 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 treaty_builder.h, misc.c and ifiction.c\r
14  *\r
15  * Header note: to add support for new executable chunk types, see\r
16  * TranslateExec.\r
17  *\r
18  * This file defines a Treaty of Babel compatable module for handling blorb\r
19  * files.  However, blorb files are not themselves a babel format. This module\r
20  * is used internally by the babel program to handle blorbs.\r
21  *\r
22  * As a result, if GET_STORY_FILE_IFID_SEL returns NO_REPLY_RV,\r
23  * you should check the story file against the babel registry before resorting\r
24  * to the default IFID calculation.\r
25  *\r
26  */\r
27 #define FORMAT blorb\r
28 #define HOME_PAGE "http://eblong.com/zarf/blorb"\r
29 #define FORMAT_EXT ".blorb,.blb,.zblorb,.zlb,.gblorb,.glb"\r
30 #define CONTAINER_FORMAT\r
31 #include "treaty_builder.h"\r
32 #include <stdlib.h>\r
33 #include <ctype.h>\r
34 \r
35 extern TREATY treaty_registry[];\r
36 /* The following is the translation table of Blorb chunk types to\r
37    babel formats.  it is NULL-terminated. */\r
38 static char *TranslateExec[] = { "ZCOD", "zcode",\r
39                                  "GLUL", "glulx",\r
40                                  "TAD2", "tads2",\r
41                                  "TAD3", "tads3",\r
42                                  NULL, NULL };\r
43 \r
44 void *my_malloc(int32, char *);\r
45 int32 ifiction_get_IFID(char *, char *, int32);\r
46 \r
47 static int32 read_int(void *inp)\r
48 {\r
49   unsigned char *mem=(unsigned char *)inp;\r
50   int32 i4 = mem[0],\r
51                     i3 = mem[1],\r
52                     i2 = mem[2],\r
53                     i1 = mem[3];\r
54   return i1 | (i2<<8) | (i3<<16) | (i4<<24);\r
55 }\r
56 \r
57 \r
58 static int32 blorb_get_chunk(void *blorb_file, int32 extent, char *id, int32 *begin, int32 *output_extent)\r
59 {\r
60  int32 i=12, j;\r
61  while(i<extent-8)\r
62  {\r
63   if (memcmp(((char *)blorb_file)+i,id,4)==0)\r
64   {\r
65    *output_extent=read_int((char *)blorb_file+i+4);\r
66    if (*output_extent > extent) return NO_REPLY_RV;\r
67    *begin=i+8;\r
68    return 1;\r
69   }\r
70 \r
71   j=read_int((char *)blorb_file+i+4);\r
72   if (j%2) j++;\r
73   i+=j+8;\r
74 \r
75  }\r
76  return NO_REPLY_RV;\r
77 }\r
78 static int32 blorb_get_resource(void *blorb_file, int32 extent, char *rid, int32 number, int32 *begin, int32 *output_extent)\r
79 {\r
80  int32 ridx_len;\r
81  int32 i,j;\r
82  void *ridx;\r
83  if (blorb_get_chunk(blorb_file, extent,"RIdx",&i,&ridx_len)==NO_REPLY_RV)\r
84   return NO_REPLY_RV;\r
85 \r
86  ridx=(char *)blorb_file+i+4;\r
87  ridx_len=read_int((char *)blorb_file+i);\r
88  for(i=0;i<ridx_len;i++)\r
89  { \r
90   if(memcmp((char *)ridx+(i*12),rid,4)==0 && read_int((char *)ridx+(i*12)+4)==number)\r
91   {\r
92    j=i;\r
93    i=read_int((char *)ridx+(j*12)+8);\r
94    *begin=i+8;\r
95    *output_extent=read_int((char *)blorb_file+i+4);\r
96    return 1;\r
97   }\r
98  }\r
99  return NO_REPLY_RV;\r
100 }\r
101 static int32 blorb_get_story_file(void *blorb_file, int32 extent, int32 *begin, int32 *output_extent)\r
102 {\r
103  return blorb_get_resource(blorb_file, extent, "Exec", 0, begin, output_extent);\r
104 \r
105 }\r
106 \r
107 static int32 get_story_extent(void *blorb_file, int32 extent)\r
108 {\r
109  int32 i,j;\r
110  if (blorb_get_resource(blorb_file, extent, "Exec", 0, &i, &j))\r
111  {\r
112   return j;\r
113  }\r
114  return NO_REPLY_RV;\r
115 \r
116 }\r
117 static int32 get_story_file(void *blorb_file, int32 extent, void *output, int32 output_extent)\r
118 {\r
119  int32 i,j;\r
120  if (blorb_get_resource(blorb_file, extent, "Exec", 0, &i, &j))\r
121  {\r
122   ASSERT_OUTPUT_SIZE(j);\r
123   memcpy(output,(char *)blorb_file+i,j);\r
124   return j;\r
125  }\r
126  return NO_REPLY_RV;\r
127 \r
128 }\r
129 \r
130 char *blorb_chunk_for_name(char *name)\r
131 {\r
132  static char buffer[5];\r
133  int j;\r
134  for(j=0;TranslateExec[j];j+=2)\r
135   if (strcmp(name,TranslateExec[j+1])==0) return TranslateExec[j];\r
136  for(j=0;j<4 && name[j];j++) buffer[j]=toupper(buffer[j]);\r
137  while(j<4) buffer[j++]=' ';\r
138  buffer[4]=0;\r
139  return buffer;\r
140 \r
141 }\r
142 static char *blorb_get_story_format(void *blorb_file, int32 extent)\r
143 {\r
144  int32 i, j;\r
145 \r
146  for(j=0;treaty_registry[j];j++)\r
147  {\r
148   static char fn[512];\r
149   treaty_registry[j](GET_FORMAT_NAME_SEL,NULL,0,fn,512);\r
150   if (blorb_get_chunk(blorb_file,extent,blorb_chunk_for_name(fn),&i, &i)) return fn;\r
151  }\r
152  return NULL;\r
153 }\r
154 \r
155 static int32 get_story_format(void *blorb_file, int32 extent, char *output, int32 output_extent)\r
156 {\r
157  char *o;\r
158  o=blorb_get_story_format(blorb_file, extent);\r
159  if (!o) return NO_REPLY_RV;\r
160  ASSERT_OUTPUT_SIZE((signed) strlen(o)+1);\r
161  strcpy(output,o);\r
162  return strlen(o)+1;\r
163 }\r
164 static int32 get_story_file_metadata_extent(void *blorb_file, int32 extent)\r
165 {\r
166  int32 i,j;\r
167  if (blorb_get_chunk(blorb_file,extent,"IFmd",&i,&j)) return j+1;\r
168  return NO_REPLY_RV;\r
169 }\r
170 static int32 blorb_get_cover(void *blorb_file, int32 extent, int32 *begin, int32 *output_extent)\r
171 {\r
172  int i,j;\r
173  if (blorb_get_chunk(blorb_file,extent,"Fspc",&i,&j))\r
174  {\r
175   if (j<4) return NO_REPLY_RV;\r
176   i=read_int((char *)blorb_file+i);\r
177   if (!blorb_get_resource(blorb_file,extent,"Pict",i,&i,&j)) return NO_REPLY_RV;\r
178   *begin=i;\r
179   *output_extent=j;\r
180   if (memcmp((char *)blorb_file+i-8,"PNG ",4)==0) return PNG_COVER_FORMAT;\r
181   else if (memcmp((char *)blorb_file+i-8,"JPEG",4)==0) return JPEG_COVER_FORMAT;\r
182  }\r
183  return NO_REPLY_RV;\r
184 \r
185 }\r
186 \r
187 static int32 get_story_file_cover_extent(void *blorb_file, int32 extent)\r
188 {\r
189  int32 i,j;\r
190  if (blorb_get_cover(blorb_file,extent,&i,&j)) return j;\r
191  return NO_REPLY_RV;\r
192 }\r
193 \r
194 static int32 get_story_file_cover_format(void *blorb_file, int32 extent)\r
195 {\r
196  int32 i,j;\r
197  return blorb_get_cover(blorb_file, extent, &i,&j);\r
198 }\r
199 \r
200 static int32 get_story_file_IFID(void *b, int32 e, char *output, int32 output_extent)\r
201 {\r
202  int32 j;\r
203  char *md;\r
204  j=get_story_file_metadata_extent(b,e);\r
205  if (j<=0) return NO_REPLY_RV;\r
206  md=(char *)my_malloc(j, "Metadata buffer");\r
207  j=get_story_file_metadata(b,e,md,j);\r
208  if (j<=0) return NO_REPLY_RV;\r
209 \r
210  j=ifiction_get_IFID(md,output,output_extent);\r
211  free(md);\r
212  return j;\r
213 }\r
214 \r
215 static int32 get_story_file_metadata(void *blorb_file, int32 extent, char *output, int32 output_extent)\r
216 {\r
217  int32 i,j;\r
218  if (!blorb_get_chunk(blorb_file, extent,"IFmd",&i,&j)) return NO_REPLY_RV;\r
219  ASSERT_OUTPUT_SIZE(j+1);\r
220  memcpy(output,(char *)blorb_file+i,j);\r
221  output[j]=0;\r
222  return j+1;\r
223 }\r
224 static int32 get_story_file_cover(void *blorb_file, int32 extent, void *output, int32 output_extent)\r
225 {\r
226  int32 i,j;\r
227  if (!blorb_get_cover(blorb_file, extent,&i,&j)) return NO_REPLY_RV;\r
228  ASSERT_OUTPUT_SIZE(j);\r
229  memcpy(output,(char *)blorb_file+i,j);\r
230  return j;\r
231 }\r
232 \r
233 static int32 claim_story_file(void *story_file, int32 extent)\r
234 {\r
235  int i;\r
236 \r
237  if (extent<16 ||\r
238      memcmp(story_file,"FORM",4) ||\r
239      memcmp((char *)story_file+8,"IFRS",4) \r
240     ) i= INVALID_STORY_FILE_RV;\r
241  else i= NO_REPLY_RV;\r
242  \r
243  return i;\r
244 \r
245 }\r