1 /* babel_handler.c dispatches Treaty of Babel queries to the treaty modules
\r
2 * (c) 2006 By L. Ross Raszewski
\r
4 * This code is freely usable for all purposes.
\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
10 * 543 Howard Street, 5th Floor,
\r
11 * San Francisco, California, 94105, USA.
\r
13 * This file depends upon register.c, misc.c, babel.h, and treaty.h
\r
14 * and L. Peter Deutsch's md5.c
\r
16 * char *babel_init(char *filename)
\r
17 * Initializes babel to use the specified file. MUST be called before
\r
18 * babel_treaty. Returns the human-readable name of the format
\r
19 * or NULL if the format is not known. Do not call babel_treaty unless
\r
20 * babel_init returned a nonzero value.
\r
21 * The returned string will be the name of a babel format, possibly
\r
22 * prefixed by "blorbed " to indicate that babel will process this file
\r
24 * int32 babel_treaty(int32 selector, void *output, void *output_extent)
\r
25 * Dispatches the call to the treaty handler for the currently loaded
\r
27 * When processing a blorb, all treaty calls will be deflected to the
\r
28 * special blorb handler. For the case of GET_STORY_FILE_IFID_SEL,
\r
29 * The treaty handler for the underlying format will be called if an
\r
30 * IFID is not found in the blorb resources.
\r
31 * void babel_release()
\r
32 * Frees all resources allocated during babel_init.
\r
33 * You should do this even if babel_init returned NULL.
\r
34 * After this is called, do not call babel_treaty until after
\r
35 * another successful call to babel_init.
\r
36 * char *babel_get_format()
\r
37 * Returns the same value as the last call to babel_init (ie, the format name)
\r
38 * int32 babel_md5_ifid(char *buffer, int extent);
\r
39 * Generates an MD5 IFID from the loaded story. Returns zero if something
\r
40 * went seriously wrong.
\r
42 * If you wish to use babel in multiple threads, you must use the contextualized
\r
43 * versions of the above functions.
\r
44 * Each function above has a companion function whose name ends in _ctx (eg.
\r
45 * "babel_treaty_ctx") which takes one additional argument. This argument is
\r
46 * the babel context. A new context is returned by void *ctx=get_babel_ctx(),
\r
47 * and should be released when finished by calling release_babel_ctx(ctx);
\r
58 void *my_malloc(int, char *);
\r
60 struct babel_handler
\r
62 TREATY treaty_handler;
\r
63 TREATY treaty_backup;
\r
65 int32 story_file_extent;
\r
66 void *story_file_blorbed;
\r
67 int32 story_file_blorbed_extent;
\r
73 static struct babel_handler default_ctx;
\r
75 extern TREATY treaty_registry[];
\r
76 extern TREATY container_registry[];
\r
78 static char *deeper_babel_init(char *story_name, void *bhp)
\r
80 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
84 static char buffer[TREATY_MINIMUM_EXTENT];
\r
86 char buffert[TREATY_MINIMUM_EXTENT];
\r
90 ext=strrchr(story_name,'.');
\r
91 if (ext) for(i=0;ext[i];i++) ext[i]=tolower(ext[i]);
\r
95 if (ext) /* pass 1: try best candidates */
\r
96 for(i=0;container_registry[i];i++)
\r
97 if (container_registry[i](GET_FILE_EXTENSIONS_SEL,NULL,0,buffer,TREATY_MINIMUM_EXTENT) >=0 &&
\r
98 strstr(buffer,ext) &&
\r
99 container_registry[i](CLAIM_STORY_FILE_SEL,bh->story_file,bh->story_file_extent,NULL,0)>=NO_REPLY_RV)
\r
101 if (!ext || !container_registry[i]) /* pass 2: try all candidates */
\r
104 for(i=0;container_registry[i];i++)
\r
105 {int l=container_registry[i](CLAIM_STORY_FILE_SEL,bh->story_file,bh->story_file_extent,NULL,0);
\r
107 if (l==VALID_STORY_FILE_RV)
\r
109 else if (l==NO_REPLY_RV && best_candidate < 0) best_candidate=i;
\r
112 if (!container_registry[i] && best_candidate >=0) { bh->auth=0; i=best_candidate; }
\r
113 if (container_registry[i])
\r
115 char buffer2[TREATY_MINIMUM_EXTENT];
\r
117 bh->treaty_handler=container_registry[i];
\r
118 container_registry[i](GET_FORMAT_NAME_SEL,NULL,0,buffert,TREATY_MINIMUM_EXTENT);
\r
121 bh->story_file_blorbed_extent=container_registry[i](CONTAINER_GET_STORY_EXTENT_SEL,bh->story_file,bh->story_file_extent,NULL,0);
\r
122 if (bh->story_file_blorbed_extent>0) bh->story_file_blorbed=my_malloc(bh->story_file_blorbed_extent, "contained story file");
\r
123 if (bh->story_file_blorbed_extent<=0 ||
\r
124 container_registry[i](CONTAINER_GET_STORY_FORMAT_SEL,bh->story_file,bh->story_file_extent,buffer2,TREATY_MINIMUM_EXTENT)<0 ||
\r
125 container_registry[i](CONTAINER_GET_STORY_FILE_SEL,bh->story_file,bh->story_file_extent,bh->story_file_blorbed,bh->story_file_blorbed_extent)<=0
\r
129 for(i=0;treaty_registry[i];i++)
\r
130 if (treaty_registry[i](GET_FORMAT_NAME_SEL,NULL,0,buffer,TREATY_MINIMUM_EXTENT)>=0 &&
\r
131 strcmp(buffer,buffer2)==0 &&
\r
132 treaty_registry[i](CLAIM_STORY_FILE_SEL,bh->story_file_blorbed,bh->story_file_blorbed_extent,NULL,0)>=NO_REPLY_RV)
\r
134 if (!treaty_registry[i])
\r
136 bh->treaty_backup=treaty_registry[i];
\r
137 sprintf(buffer,"%sed %s",buffert,buffer2);
\r
144 if (ext) /* pass 1: try best candidates */
\r
145 for(i=0;treaty_registry[i];i++)
\r
146 if (treaty_registry[i](GET_FILE_EXTENSIONS_SEL,NULL,0,buffer,TREATY_MINIMUM_EXTENT) >=0 &&
\r
147 strstr(buffer,ext) &&
\r
148 treaty_registry[i](CLAIM_STORY_FILE_SEL,bh->story_file,bh->story_file_extent,NULL,0)>=NO_REPLY_RV)
\r
150 if (!ext || !treaty_registry[i]) /* pass 2: try all candidates */
\r
153 for(i=0;treaty_registry[i];i++)
\r
155 l=treaty_registry[i](CLAIM_STORY_FILE_SEL,bh->story_file,bh->story_file_extent,NULL,0);
\r
157 if (l==VALID_STORY_FILE_RV)
\r
159 else if (l==NO_REPLY_RV && best_candidate < 0) best_candidate=i;
\r
162 if (!treaty_registry[i])
\r
163 if (best_candidate>0) { i=best_candidate; bh->auth=0; }
\r
165 bh->treaty_handler=treaty_registry[i];
\r
167 if (bh->treaty_handler(GET_FORMAT_NAME_SEL,NULL,0,buffer,TREATY_MINIMUM_EXTENT)>=0)
\r
174 static char *deep_babel_init(char *story_name, void *bhp)
\r
176 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
179 bh->treaty_handler=NULL;
\r
180 bh->treaty_backup=NULL;
\r
181 bh->story_file=NULL;
\r
182 bh->story_file_extent=0;
\r
183 bh->story_file_blorbed=NULL;
\r
184 bh->story_file_blorbed_extent=0;
\r
185 bh->format_name=NULL;
\r
186 file=fopen(story_name, "rb");
\r
187 if (!file) return NULL;
\r
188 fseek(file,0,SEEK_END);
\r
189 bh->story_file_extent=ftell(file);
\r
190 fseek(file,0,SEEK_SET);
\r
192 bh->story_file=my_malloc(bh->story_file_extent,"story file storage");
\r
193 fread(bh->story_file,1,bh->story_file_extent,file);
\r
196 return deeper_babel_init(story_name, bhp);
\r
199 char *babel_init_ctx(char *sf, void *bhp)
\r
201 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
203 b=deep_babel_init(sf,bh);
\r
204 if (b) bh->format_name=strdup(b);
\r
207 char *babel_init(char *sf)
\r
209 return babel_init_ctx(sf, &default_ctx);
\r
212 char *babel_init_raw_ctx(void *sf, int32 extent, void *bhp)
\r
214 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
216 bh->treaty_handler=NULL;
\r
217 bh->treaty_backup=NULL;
\r
218 bh->story_file=NULL;
\r
219 bh->story_file_extent=0;
\r
220 bh->story_file_blorbed=NULL;
\r
221 bh->story_file_blorbed_extent=0;
\r
222 bh->format_name=NULL;
\r
223 bh->story_file_extent=extent;
\r
225 bh->story_file=my_malloc(bh->story_file_extent,"story file storage");
\r
226 memcpy(bh->story_file,sf,extent);
\r
228 b=deeper_babel_init(NULL, bhp);
\r
229 if (b) bh->format_name=strdup(b);
\r
232 char *babel_init_raw(void *sf, int32 extent)
\r
234 return babel_init_raw_ctx(sf, extent, &default_ctx);
\r
237 void babel_release_ctx(void *bhp)
\r
239 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
240 if (bh->story_file) free(bh->story_file);
\r
241 bh->story_file=NULL;
\r
242 if (bh->story_file_blorbed) free(bh->story_file_blorbed);
\r
243 bh->story_file_blorbed=NULL;
\r
244 if (bh->format_name) free(bh->format_name);
\r
245 bh->format_name=NULL;
\r
247 void babel_release()
\r
249 babel_release_ctx(&default_ctx);
\r
251 int32 babel_md5_ifid_ctx(char *buffer, int32 extent, void *bhp)
\r
253 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
256 unsigned char ob[16];
\r
257 if (extent <33 || bh->story_file==NULL)
\r
260 md5_append(&md5,bh->story_file,bh->story_file_extent);
\r
261 md5_finish(&md5,ob);
\r
263 sprintf(buffer+(2*i),"%02X",ob[i]);
\r
268 int32 babel_md5_ifid(char *buffer, int32 extent)
\r
270 return babel_md5_ifid_ctx(buffer, extent,
\r
274 int32 babel_treaty_ctx(int32 sel, void *output, int32 output_extent,void *bhp)
\r
277 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
278 if (!(sel & TREATY_SELECTOR_INPUT) && bh->blorb_mode)
\r
279 rv=bh->treaty_backup(sel,bh->story_file_blorbed,bh->story_file_blorbed_extent,output, output_extent);
\r
282 rv=bh->treaty_handler(sel,bh->story_file,bh->story_file_extent,output,output_extent);
\r
283 if ((!rv|| rv==UNAVAILABLE_RV) && bh->blorb_mode)
\r
284 rv=bh->treaty_backup(sel,bh->story_file_blorbed,bh->story_file_blorbed_extent,output, output_extent);
\r
286 if (!rv && sel==GET_STORY_FILE_IFID_SEL)
\r
287 return babel_md5_ifid_ctx(output,output_extent, bh);
\r
288 if (rv==INCOMPLETE_REPLY_RV && sel==GET_STORY_FILE_IFID_SEL)
\r
289 return babel_md5_ifid_ctx((void *)((char *) output+strlen((char *)output)),
\r
290 output_extent-strlen((char *)output),
\r
295 int32 babel_treaty(int32 sel, void *output, int32 output_extent)
\r
297 return babel_treaty_ctx(sel, output, output_extent, &default_ctx);
\r
299 char *babel_get_format_ctx(void *bhp)
\r
301 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
302 return bh->format_name;
\r
304 char *babel_get_format()
\r
306 return babel_get_format_ctx(&default_ctx);
\r
308 void *get_babel_ctx()
\r
310 return my_malloc(sizeof(struct babel_handler), "babel handler context");
\r
312 void release_babel_ctx(void *b)
\r
317 int32 babel_get_length_ctx(void *bhp)
\r
319 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
320 return bh->story_file_extent;
\r
322 int32 babel_get_length()
\r
324 return babel_get_length_ctx(&default_ctx);
\r
327 int32 babel_get_authoritative_ctx(void *bhp)
\r
329 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
332 int32 babel_get_authoritative()
\r
334 return babel_get_authoritative_ctx(&default_ctx);
\r
336 void *babel_get_file_ctx(void *bhp)
\r
338 struct babel_handler *bh=(struct babel_handler *) bhp;
\r
339 return bh->story_file;
\r
341 void *babel_get_file()
\r
343 return babel_get_file_ctx(&default_ctx);
\r
346 int32 babel_get_story_length_ctx(void *ctx)
\r
348 struct babel_handler *bh=(struct babel_handler *) ctx;
\r
349 if (bh->blorb_mode) return bh->story_file_blorbed_extent;
\r
350 return bh->story_file_extent;
\r
352 int32 babel_get_story_length()
\r
355 return babel_get_story_length_ctx(&default_ctx);
\r
357 void *babel_get_story_file_ctx(void *ctx)
\r
359 struct babel_handler *bh=(struct babel_handler *) ctx;
\r
360 if (bh->blorb_mode) return bh->story_file_blorbed;
\r
361 return bh->story_file;
\r
363 void *babel_get_story_file()
\r
365 return babel_get_story_file_ctx(&default_ctx);
\r