hbmap: fix iterator truncation when size_t < 32bit
[rofl0r-agsutils.git] / DataFile.c
blob6ea4a128865aa843f7f26d4227f85376c8a1df81
1 #define _GNU_SOURCE
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include "DataFile.h"
6 #include "Script.h"
8 #ifdef _WIN32
9 #define PSEP '\\'
10 #else
11 #define PSEP '/'
12 #endif
14 void ADF_close(ADF* a) {
15 AF_close(a->f);
18 ASI *ADF_get_global_script(ADF* a) {
19 return &a->globalscript;
22 ASI *ADF_get_dialog_script(ADF* a) {
23 return &a->dialogscript;
26 ASI *ADF_get_script(ADF* a, size_t index) {
27 if(index >= a->scriptcount) return 0;
28 return &a->scripts[index];
31 size_t ADF_get_scriptcount(ADF* a) {
32 return a->scriptcount;
35 typedef enum interaction_type {
36 it_char = 0,
37 it_inventory,
38 it_max
39 } interaction_type;
41 static int ADF_read_interaction(ADF *a, interaction_type t) {
42 /* deserialize_interaction_scripts */
43 static const size_t iter_start[it_max] = {
44 [it_char] = 0,
45 [it_inventory] = 1,
47 size_t *countmap[it_max] = {
48 [it_char] = &a->game.charactercount,
49 [it_inventory] = &a->game.inventorycount,
50 }, l = *countmap[t], i = iter_start[t];
51 char buf[200];
52 for(; i < l; i++) {
53 size_t j = 0, evcnt = AF_read_uint(a->f);
54 for(; j < evcnt; j++) {
55 if(!AF_read_string(a->f, buf, 200)) return 0; /* function names of interaction scripts */
58 return 1;
61 static int deserialize_command_list(ADF *a) {
62 size_t l = AF_read_uint(a->f);
63 AF_read_uint(a->f); /*timesrun*/
64 size_t i;
65 char childs[1024];
66 assert(l < sizeof(childs));
67 for(i = 0; i < l; i++) {
68 AF_read_uint(a->f); // unused
69 AF_read_uint(a->f); // type
70 size_t j = 0;
71 for(; j < 5; j++) {
72 char buf[4];
73 if(1 != AF_read(a->f, buf, 1)) // valType
74 return 0;
75 if(3 != AF_read(a->f, buf, 3)) // padding
76 return 0;
77 AF_read_uint(a->f); // val
78 AF_read_uint(a->f); // extra
80 childs[i] = !!AF_read_uint(a->f); // children
81 AF_read_uint(a->f); // parent
83 for(i = 0; i < l; i++) {
84 if(childs[i]) deserialize_command_list(a);
86 return 1;
89 static int ADF_read_interaction2x(ADF *a, interaction_type t) {
90 /* deserialize_new_interaction */
91 size_t *countmap[it_max] = {
92 [it_char] = &a->game.charactercount,
93 [it_inventory] = &a->game.inventorycount,
94 }, l = *countmap[t], i = 0;
95 for(; i < l; i++) {
96 int response[32];
97 if(AF_read_uint(a->f) != 1) continue;
98 size_t evcnt = AF_read_uint(a->f);
99 if(evcnt > 30) return 0;
100 AF_read_junk(a->f, evcnt * sizeof(int)); /*event types */
101 size_t j = 0;
102 for(; j < evcnt; j++)
103 response[j] = AF_read_int(a->f);
104 for(j = 0; j < evcnt; j++)
105 if(response[j]) {
106 if(!deserialize_command_list(a))
107 return 0;
110 return 1;
113 static int ADF_read_gamebase(ADF *a) {
114 /* acroom.h: 2881. void ReadFile() */
115 size_t l;
116 unsigned x;
117 char game_name[52];
118 l = 50 /* game name */ + 2 /*padding*/;
119 if(!AF_read(a->f, game_name, l)) return 0;
120 /* 100 options */
121 if(!AF_read_junk(a->f, 100*4)) return 0;
122 l = 256; /* 256 "paluses", unsigned char*/
123 if(!AF_read_junk(a->f, l)) return 0;
124 l = 256 * 4; /*sizeof color, read into defpal*/
125 if(!AF_read_junk(a->f, l)) return 0;
126 a->game.viewcount = AF_read_uint(a->f);
127 a->game.charactercount = AF_read_uint(a->f);
128 AF_read_uint(a->f); /* character of player*/
129 AF_read_uint(a->f); /* totalscore*/
130 a->game.inventorycount = AF_read_ushort(a->f);
131 AF_read_ushort(a->f); /* padding */
132 a->game.dialogcount = AF_read_uint(a->f);
133 AF_read_uint(a->f); /* numdlgmessage*/
134 a->game.fontcount = AF_read_uint(a->f);
135 a->game.color_depth = AF_read_uint(a->f); /* color depth - offset 0x710 into game28.dta */
136 AF_read_uint(a->f); /* target_win */
137 AF_read_uint(a->f);/* dialog_bullet */
138 AF_read_ushort(a->f);/* hotdot */
139 AF_read_ushort(a->f);/* hotdotouter */
140 AF_read_uint(a->f);/* uniqueid */
141 AF_read_uint(a->f);/* numgui */
142 a->game.cursorcount = AF_read_uint(a->f);
143 x = AF_read_uint(a->f);/* default_resolution */
144 if(a->version >= 43 /* 3.3.0 */ && x == 8 /* custom resolution */) {
145 /* 2 ints with the custom width and height */
146 if(!AF_read_junk(a->f, 8)) return 0;
148 AF_read_uint(a->f);/* default_lipsync_frame */
149 AF_read_uint(a->f);/* invhotdotsprite */
150 l = 4 * 17; /* reserved */
151 if(!AF_read_junk(a->f, l)) return 0;
152 a->game.globalmessagecount = 0;
154 int buf[500], n; /* 500 global message numbers */;
155 if(!AF_read(a->f, buf, sizeof(buf))) return 0;
156 for(n = 0; n < 500; ++n)
157 if(buf[n]) a->game.globalmessagecount++;
159 a->game.hasdict = !!AF_read_int(a->f);/* dict */
160 AF_read_uint(a->f);/* globalscript */
161 AF_read_uint(a->f);/* chars */
162 AF_read_uint(a->f);/* compiled_script */
163 return 1;
166 static int ADF_read_dictionary(ADF *a) {
167 /* acroom.h:1547 */
168 size_t i,l = AF_read_uint(a->f);
169 for(i = 0; i < l; i++) {
170 /* length of encrypted string */
171 size_t e = AF_read_uint(a->f);
172 if(!AF_read_junk(a->f, e)) return 0;
173 AF_read_short(a->f); /* wordnum */
175 return 1;
178 static int ADF_read_view(ADF *a) {
179 size_t i, numloops = AF_read_ushort(a->f);
180 for(i=0; i<numloops; ++i) {
181 size_t numframes = AF_read_ushort(a->f);
182 size_t l = 4 /* flags */ + numframes * (4/*pic*/+2/*xoffs*/+2/*yoffs*/+2/*speed*/+2/*padding*/+4/*flags*/+4/*sound*/+8/*reserved*/);
183 if(!AF_read_junk(a->f, l)) return 0;
185 return 1;
188 static int ADF_read_view2x(ADF *a) {
189 size_t l = 2 /* numloops */ + (16*2) /* numframes */
190 + 2 /* padding? */ + (16*4) /* loopflags */
191 + (16*20*(4/*pic*/+2/*xoffs*/+2/*yoffs*/+2/*speed*/+2/*padding*/+4/*flags*/+4/*sound*/+8/*reserved*/)) /* viewframes */;
192 return AF_read_junk(a->f, l);
195 static int ADF_read_characters(ADF *a) {
196 #define MAX_INV 301
197 #define MAX_SCRIPT_NAME_LEN 20
198 struct CharacterInfo {
199 int defview;
200 int talkview;
201 int view;
202 int room, prevroom;
203 int x, y, wait;
204 int flags;
205 short following;
206 short followinfo;
207 int idleview;
208 short idletime, idleleft;
209 short transparency;
210 short baseline;
211 int activeinv;
212 int talkcolor;
213 int thinkview;
214 short blinkview, blinkinterval;
215 short blinktimer, blinkframe;
216 short walkspeed_y, pic_yoffs;
217 int z;
218 int walkwait;
219 short speech_anim_speed, reserved1;
220 short blocking_width, blocking_height;
221 int index_id;
222 short pic_xoffs, walkwaitcounter;
223 short loop, frame;
224 short walking, animating;
225 short walkspeed, animspeed;
226 short inv[MAX_INV];
227 short actx, acty;
228 char name[40];
229 char scrname[MAX_SCRIPT_NAME_LEN];
230 char on;
231 } character;
232 size_t i;
233 a->characternames = malloc(a->game.charactercount*sizeof(char*));
234 a->characterscriptnames = malloc(a->game.charactercount*sizeof(char*));
235 for(i=0; i<a->game.charactercount; ++i) {
236 if(sizeof(character) != AF_read(a->f, &character, sizeof(character))) return 0;
237 if(strlen(character.name) >= sizeof(character.name)) return 0;
238 if(strlen(character.scrname) >= sizeof(character.scrname)) return 0;
239 a->characternames[i] = strdup(character.name);
240 a->characterscriptnames[i] = strdup(character.scrname);
242 return 1;
245 int ADF_find_datafile(const char *dir, char *fnbuf, size_t flen)
247 size_t l = strlen(dir);
248 if(l >= flen - 20) return 0;
249 memcpy(fnbuf, dir, l);
250 char* p = fnbuf + l;
251 *p = PSEP; p++;
252 memcpy(p, "game28.dta", sizeof("game28.dta"));
253 AF f;
254 if(!AF_open(&f, fnbuf)) {
255 memcpy(p, "ac2game.dta", sizeof("ac2game.dta"));
256 if(!AF_open(&f, fnbuf)) return 0;
258 AF_close(&f);
259 return 1;
262 int ADF_read_cursors(ADF* a) {
263 a->cursornames = malloc(a->game.cursorcount * sizeof(char*));
264 if(!a->cursornames) return 0;
266 unsigned i;
267 for(i=0; i<a->game.cursorcount; ++i) {
268 char buf[24];
269 if(24 != AF_read(a->f, buf, 24)) return 0;
270 if(buf[19] != 0) return 0;
271 a->cursornames[i] = strdup(buf+10);
273 return 1;
276 int ADF_read_dialogtopics(ADF *a) {
277 /* Common/acroom.h:2722 */
278 a->dialog_codesize = malloc(a->game.dialogcount*sizeof(short));
279 #define MAXTOPICOPTIONS 30
280 size_t i, l; // = (150*MAXTOPICOPTIONS)+(4*MAXTOPICOPTIONS)+4+(2*MAXTOPICOPTIONS)+2+2+4+4;
281 for(i=0; i<a->game.dialogcount; ++i) {
282 /* optionnames + optionflags + optionscripts + entrypoints*/
283 l = (150*MAXTOPICOPTIONS)+(4*MAXTOPICOPTIONS)+4+(2*MAXTOPICOPTIONS);
284 if(!AF_read_junk(a->f, l)) return 0;
285 unsigned short startupentrypoint = AF_read_ushort(a->f);
286 a->dialog_codesize[i] = AF_read_ushort(a->f);
287 if(!AF_read_junk(a->f, 8 /* numoptions+topicFlags*/)) return 0;
289 return 1;
292 static void dialog_decrypt_text(char *s, int len) {
293 unsigned i = 0;
294 while (i < len) {
295 *s -= "Avis Durgan"[i % 11];
296 if (!*s) break;
297 ++i; ++s;
301 static int is_zeroterminated(char *s, size_t maxsize) {
302 char *p = s, *e = s + maxsize;
303 while(p < e) if(!*(p++)) return 1;
304 return 0;
307 #define MAX_GUIOBJ_SCRIPTNAME_LEN 25
308 #define MAX_GUIOBJ_EVENTHANDLER_LEN 30
309 static int ADF_read_gui_object(ADF *a, unsigned guiver) {
310 if(!AF_read_junk(a->f, guiver >= 119 ? 6*4 : 7*4)) return 0;
311 char buf[512]; /* arbitrary limit.
312 ags commit ed06eb64 made away with any length restrictions;
313 that was done when kGuiVersion_340 = 118 was current. */
314 size_t i;
315 if(guiver >= 106) {
316 if(!AF_read_string(a->f, buf, guiver >= 118 ? sizeof buf : MAX_GUIOBJ_SCRIPTNAME_LEN)) return 0;
318 if(guiver >= 108) {
319 unsigned numev = AF_read_uint(a->f);
320 for(i=0; i<numev; ++i) {
321 if(!AF_read_string(a->f, buf, guiver >= 118 ? sizeof buf : MAX_GUIOBJ_EVENTHANDLER_LEN+1)) return 0;
324 return 1;
327 static int AF_read_string_with_length(AF *f, char *buf, size_t maxlen) {
328 unsigned len = AF_read_uint(f);
329 if(len >= maxlen) return 0;
330 if(len && !AF_read(f, buf, len)) return 0;
331 buf[len] = 0;
332 return 1;
335 int ADF_read_guis(ADF *a) {
336 #define MAX_OBJS_ON_GUI 30
337 #define FAIL() goto fail
338 #if 0
339 volatile unsigned fail_line = 0;
340 #undef FAIL
341 #define FAIL() do { fail_line = __LINE__; goto fail; } while(0)
342 #endif
343 /* Engine/acgui.cpp:1471 */
344 unsigned x = AF_read_uint(a->f);
345 if(x != 0xCAFEBEEF) return 0;
346 int guiver, n = AF_read_uint(a->f);
347 if(n >= 100) {
348 guiver = n;
349 n = AF_read_uint(a->f);
350 } else {
351 guiver = 0;
353 if(n < 0 || n > 1000) return 0;
354 a->guicount = n;
355 a->guinames = malloc(sizeof(char*)*a->guicount);
356 size_t i;
357 for(i = 0; i < a->guicount; ++i) {
358 char buf[512];
359 if(guiver < 119 /* 3.5.0 */) {
360 if(!AF_read_junk(a->f, 4 /*vtext*/)) FAIL();
362 if(guiver >= 118) /* 3.4.0 */ {
363 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) FAIL();
364 } else {
365 if(16 != AF_read(a->f, buf, 16)) FAIL();
366 if(!is_zeroterminated(buf, 16)) FAIL();
368 if(!buf[0]) snprintf(buf, sizeof buf, "GUI%zu", i);
369 a->guinames[i] = strdup(buf);
370 if(guiver >= 118) {
371 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) FAIL();
372 } else {
373 if(!AF_read_junk(a->f, 20 /* clickEventHandler */)) FAIL();
375 if(!AF_read_junk(a->f, guiver<119 ? 5*4 : 4*4 )) FAIL();
376 unsigned n_ctrls = AF_read_uint(a->f);
377 if(guiver < 118)
378 n_ctrls = MAX_OBJS_ON_GUI;
379 // have read 6 of 27 legacy ints at this point
381 size_t l;
382 if(guiver >= 119)
383 l = (10+n_ctrls) * 4;
384 else if(guiver >= 118)
385 l = (21+n_ctrls) * 4;
386 else
387 l = 21*4 /* some ints */
388 +MAX_OBJS_ON_GUI*4+MAX_OBJS_ON_GUI*4;
389 if(!AF_read_junk(a->f, l)) FAIL();
391 unsigned n_buttons = AF_read_uint(a->f);
393 for(i = 0; i < n_buttons; ++i) {
394 if(!ADF_read_gui_object(a, guiver)) FAIL();
395 char buf[512];
396 if(!AF_read_junk(a->f, guiver>=119? 9*4 : 12*4/*pic*/)) FAIL();
397 if(guiver < 119) {
398 if(!AF_read(a->f, buf, 50 /*text*/)) FAIL(); // for debugging
399 } else {
400 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) FAIL();
402 if(guiver >= 119) {
403 if(!AF_read_junk(a->f, 4 /*alignment*/)) FAIL();
404 } else if(guiver >= 111) {
405 if(!AF_read_junk(a->f, 4+4 /*alignment,reserved*/)) FAIL();
409 unsigned n_labels = AF_read_uint(a->f);
411 for(i = 0; i < n_labels; ++i) {
412 if(!ADF_read_gui_object(a, guiver)) FAIL();
413 unsigned textlen = guiver < 113 ? 200 : AF_read_uint(a->f);
414 if(!AF_read_junk(a->f, textlen + 4*3/*font*/)) FAIL();
417 unsigned n_invs = AF_read_uint(a->f);
418 for(i = 0; i < n_invs; ++i) {
419 if(!ADF_read_gui_object(a, guiver)) FAIL();
420 if(guiver >= 109) {
421 if(!AF_read_junk(a->f, guiver >= 119 ? 3*4 : 4*4 /*charid,itemw,itemh,topindex*/)) FAIL();
425 if(guiver >= 100) {
426 unsigned n_sliders = AF_read_uint(a->f);
427 for(i = 0; i < n_sliders; ++i) {
428 if(!ADF_read_gui_object(a, guiver)) FAIL();
429 unsigned n;
430 if(guiver >= 119) n = 6;
431 else if(guiver >= 104) n = 7;
432 else n = 4;
433 if(!AF_read_junk(a->f, 4*n)) FAIL();
437 if(guiver >= 101) {
438 unsigned n_texts = AF_read_uint(a->f);
439 for(i = 0; i < n_texts; ++i) {
440 if(!ADF_read_gui_object(a, guiver)) FAIL();
441 if(guiver >= 119) {
442 char buf[2048];
443 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) FAIL();
444 if(!AF_read_junk(a->f, 3*4/*font*/)) FAIL();
445 } else {
446 if(!AF_read_junk(a->f, 200/*text*/+3*4/*font*/)) FAIL();
451 if(guiver >= 102) {
452 unsigned n_lists = AF_read_uint(a->f);
453 size_t l_add1 = guiver >= 119 ? 4 : (guiver >= 112 ? 8 : 0);
454 size_t l_add2 = guiver >= 107 ? 4 : 0;
455 for(i = 0; i < n_lists; ++i) {
456 if(!ADF_read_gui_object(a, guiver)) FAIL();
457 unsigned j, n_items = AF_read_uint(a->f);
458 if(!AF_read_junk(a->f, guiver>=119 ? 3*4 : 9*4)) FAIL();
459 unsigned flags = AF_read_uint(a->f);
460 if((l_add1 + l_add2) && !AF_read_junk(a->f, l_add1 + l_add2)) FAIL();
461 for(j = 0; j < n_items; ++j) {
462 char buf[1024];
463 if(!AF_read_string(a->f, buf, sizeof buf)) FAIL();
465 if(guiver >= 114 && guiver < 119 && (flags & 4/* GLF_SGINDEXVALID */)) {
466 if(!AF_read_junk(a->f, n_items*2)) FAIL();
470 return 1;
471 fail:
472 free(a->guinames);
473 a->guinames = 0;
474 a->guicount = 0;
475 return 0;
476 #undef FAIL
479 int ADF_read_custom_property(ADF *a) {
480 unsigned i, x, propver = AF_read_uint(a->f);
481 if(propver > 2) return 0;
482 x = AF_read_uint(a->f); /* numprops */
483 for(i=0;i<x;++i) {
484 if(propver == 1) {
485 char buf[500]; /* MAX_CUSTOM_PROPERTY_VALUE_LENGTH */
486 if(!AF_read_string(a->f, buf, 200)) return 0; // propname
487 if(!AF_read_string(a->f, buf, 500)) return 0; // propval
488 } else {
489 char buf[2048];
490 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) return 0;
491 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) return 0;
494 return 1;
497 const char *AOE2str(enum ADF_open_error e) {
498 static const char err[][12] = {
499 [AOE_success] = "success",
500 [AOE_open] = "open",
501 [AOE_read] = "read",
502 [AOE_sig] = "signature",
503 [AOE_header] = "header",
504 [AOE_gamebase] = "gamebase",
505 [AOE_cursors] = "cursors",
506 [AOE_interaction] = "interaction",
507 [AOE_dictionary] = "dictionary",
508 [AOE_script] = "script",
509 [AOE_view] = "view",
510 [AOE_character] = "character",
511 [AOE_lipsync] = "lipsync",
512 [AOE_msg] = "message",
513 [AOE_dialogtopic] = "dialogtopic",
514 [AOE_dialog] = "dialog",
515 [AOE_guis] = "guis",
516 [AOE_props] = "props",
517 [AOE_views] = "views",
518 [AOE_inventories] = "inventories",
520 return err[e];
523 enum ADF_open_error ADF_open(ADF* a, const char *filename) {
524 #define FAIL(E) do { aoe = E; goto err_close; } while(0)
525 #define ERR(E) do { return E; } while(0)
526 enum ADF_open_error aoe = AOE_success;
528 char fnbuf[512];
529 size_t l, i;
531 memset(a, 0, sizeof(*a));
532 a->f = &a->f_b;
534 if(!AF_open(a->f, filename)) return AOE_open;
536 if(30 != AF_read(a->f, fnbuf, 30)) {
537 aoe = AOE_read;
538 err_close:
539 AF_close(a->f);
540 return aoe;
542 if(memcmp("Adventure Creator Game File v2", fnbuf, 30)) FAIL(AOE_sig);
543 /* the version read here is called kGameVersion_xxx in recent AGS
544 engine codebase, e.g. kGameVersion_350 == 50 */
545 a->version = AF_read_int(a->f);
546 /* here comes some version string with minor, major - we dont need it */
547 /* FIXME? newer ags does this only with version >= 12 */
548 /* 4 bytes containing the length of the string, followed by the string */
549 l = AF_read_uint(a->f);
550 if(l > 20) FAIL(AOE_header);
551 if(l != (size_t) AF_read(a->f, fnbuf, l)) goto err_close;
553 /* main_game_file.cpp:OpenMainGameFileBase */
554 if(a->version >= 48 /* kGameVersion_341 */) {
555 /* latest ags now has placed an int here: number of required capabilities */
556 l = AF_read_uint(a->f);
557 /* followed by l int/string pairs */
558 for(i=0; i<l; i++) {
559 size_t len = AF_read_uint(a->f);
560 if(!AF_read_junk(a->f, len)) FAIL(AOE_header);
563 if(!ADF_read_gamebase(a)) FAIL(AOE_gamebase);
564 if(a->version > 32) {
565 /* we're at line 11798 in Engine/ac.cpp, git revision:
566 205c56d693d903516b7b21beb454251e9489aabf - which is highly
567 recommended as the old C-style spaghetti code is more
568 readable than the current refactored OOP version. */
569 l = 40 /* guid */ + 20 /*savegame extension*/ + 50 /*savegame dir*/;
570 if(l != (size_t) AF_read(a->f, fnbuf, l)) FAIL(AOE_gamebase);
572 if(a->version < 50 /* 3.5.0 */) {
573 l = a->game.fontcount * 2; /* fontflags and fontoutline arrays [each 1b/font] */
574 if(!AF_read_junk(a->f, l)) FAIL(AOE_gamebase);
575 if(a->version >= 48) {
576 /* version == 3.4.1 have YOffset and versions >= 3.4.1.2 < 3.5.0 have YOffeset and LineSpacing ints */
577 l = a->game.fontcount * 4;
578 if(a->version == 49) l*=2;
579 if(!AF_read_junk(a->f, l)) FAIL(AOE_gamebase);
581 } else {
582 /* 3.5.0 has 5 ints per font, see gamesetupstruct.cpp */
583 l = a->game.fontcount * 4 * 5;
584 if(!AF_read_junk(a->f, l)) FAIL(AOE_gamebase);
586 // number of sprites
587 l = a->numsprites = (a->version < 24) ? 6000 : AF_read_uint(a->f);
588 a->spriteflagsstart = AF_get_pos(a->f);
589 // array of spriteflags (1 char each, max: MAX_SPRITES==30000)
590 if(!AF_read_junk(a->f, l)) FAIL(AOE_gamebase);
591 l = 68 * a->game.inventorycount; /* sizeof(InventoryItemInfo) */
592 if(!AF_read_junk(a->f, l)) FAIL(AOE_gamebase);
594 if(!ADF_read_cursors(a)) FAIL(AOE_cursors);
596 if(a->version > 32) {
597 if(!ADF_read_interaction(a, it_char)) FAIL(AOE_interaction);
598 if(!ADF_read_interaction(a, it_inventory)) FAIL(AOE_interaction);
599 } else {
600 if(!ADF_read_interaction2x(a, it_char)) FAIL(AOE_interaction);
601 if(!ADF_read_interaction2x(a, it_inventory)) FAIL(AOE_interaction);
602 a->globalvarcount = AF_read_uint(a->f);
603 l = 28 /* sizeof(InteractionVariable)*/ * a->globalvarcount;
604 if(!AF_read_junk(a->f, l)) FAIL(AOE_interaction);
606 if(a->game.hasdict)
607 if(!ADF_read_dictionary(a)) FAIL(AOE_dictionary);
608 a->scriptstart = AF_get_pos(a->f);
609 if(!ASI_read_script(a->f, &a->globalscript)) FAIL(AOE_script);
610 if(a->version > 37)
611 if(!ASI_read_script(a->f, &a->dialogscript)) FAIL(AOE_script);
612 if(a->version >= 31) {
613 a->scriptcount = AF_read_uint(a->f);
614 for(l = 0; l < a->scriptcount; l++)
615 if(!ASI_read_script(a->f, &a->scripts[l])) FAIL(AOE_script);
617 a->scriptend = AF_get_pos(a->f);
619 if(a->version > 32) {
620 for(l = 0; l < a->game.viewcount; l++)
621 if(!ADF_read_view(a)) FAIL(AOE_view);
622 } else {
623 for(l = 0; l < a->game.viewcount; l++)
624 if(!ADF_read_view2x(a)) FAIL(AOE_view);
627 if(a->version <= 19) {
628 /* skip version <= 2.51 unknown data */
629 l = AF_read_uint(a->f) * 0x204;
630 if(!AF_read_junk(a->f, l)) FAIL(AOE_view);
633 /* ... we are around line 11977 in ac.cpp at this point*/
634 if(!ADF_read_characters(a)) ERR(AOE_character);
636 if(a->version > 19 /* 2.51*/) // current AGS code says lipsync was added in 2.54==21
637 if(!AF_read_junk(a->f, 50*20/*MAXLIPSYNCFRAMES*/)) ERR(AOE_lipsync);
640 if(a->version < 26) {
641 for(l = 0; l < a->game.globalmessagecount; ++l) {
642 char buf[512];
643 if(!AF_read_string(a->f, buf, sizeof buf)) ERR(AOE_msg);
645 } else {
646 for(l = 0; l < a->game.globalmessagecount; ++l) {
647 /* length of encrypted string */
648 size_t e = AF_read_uint(a->f);
649 if(!AF_read_junk(a->f, e)) ERR(AOE_msg);
653 if(!ADF_read_dialogtopics(a)) ERR(AOE_dialogtopic);
654 /* Engine/ac.cpp:12045 */
655 a->old_dialogscripts = 0;
656 if(a->version <= 37) {
657 a->old_dialogscripts = malloc(a->game.dialogcount*sizeof(char*));
658 for(i = 0; i<a->game.dialogcount; ++i) {
659 AF_read_junk(a->f, a->dialog_codesize[i]);
660 l = AF_read_int(a->f);
661 char* buf = malloc(l);
662 AF_read(a->f, buf, l);
663 dialog_decrypt_text(buf, l);
664 a->old_dialogscripts[i] = buf;
665 //ASI scr;
666 //ASI_read_script(a, &scr);
668 if(a->version <= 25) {
669 // unencrypted dialog lines
670 // we just seek till end marker
671 // FIXME handle EOF
672 int c;
673 while((c = AF_read_uchar(a->f)) != 0xef);
674 AF_set_pos(a->f, AF_get_pos(a->f) -1);
675 } else {
676 // encrypted dialog lines
677 while(1) {
678 l = AF_read_uint(a->f);
679 if(l == 0xCAFEBEEF) break;
680 if(!AF_read_junk(a->f, l)) ERR(AOE_dialog);
682 AF_set_pos(a->f, AF_get_pos(a->f) -4);
686 if(!ADF_read_guis(a)) ERR(AOE_guis);
688 if(a->version >= 25) {
689 unsigned prop_version, x = AF_read_uint(a->f);
690 if(x != 1) ERR(AOE_props);
691 x = AF_read_uint(a->f); /* numplugins */
692 for(i = 0; i < x; ++i) {
693 char buf[80];
694 if(!AF_read_string(a->f, buf, sizeof buf)) ERR(AOE_props);
695 unsigned psize = AF_read_uint(a->f);
696 AF_read_junk(a->f, psize); /* plugin content */
698 /* CustomPropertySchema::UnSerialize */
699 prop_version = AF_read_uint(a->f);
700 if(prop_version > 2) ERR(AOE_props);
701 x = AF_read_uint(a->f); /* numprops */
702 for(i=0; i<x; ++i) {
703 if(prop_version == 1) {
704 char buf[500]; /* MAX_CUSTOM_PROPERTY_VALUE_LENGTH */
705 /* note: that 20 might actually be 200,
706 because the AGS code reserves 200 for propname,
707 but then reads only 20 */
708 /* new AGS has a comment about it:
709 NOTE: for some reason the property name stored in schema object was limited to only 20 characters, while the custom properties map could hold up to 200. Whether this was an error or design choice is unknown. */
710 if(!AF_read_string(a->f, buf, 20)) ERR(AOE_props); // propname
711 if(!AF_read_string(a->f, buf, 100)) ERR(AOE_props); //propdesc
712 if(!AF_read_string(a->f, buf, 500)) ERR(AOE_props); //defvalue
713 int foo = AF_read_uint(a->f); /* proptype */
714 } else {
715 char buf[2048];
716 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) ERR(AOE_props);
717 AF_read_uint(a->f);
718 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) ERR(AOE_props);
719 if(!AF_read_string_with_length(a->f, buf, sizeof buf)) ERR(AOE_props);
723 for(i=0; i<a->game.charactercount; ++i)
724 if(!ADF_read_custom_property(a)) ERR(AOE_props);
726 for(i=0; i<a->game.inventorycount; ++i)
727 if(!ADF_read_custom_property(a)) ERR(AOE_props);
729 a->viewnames = malloc(a->game.viewcount * sizeof(char*));
730 for(i=0; i<a->game.viewcount; ++i) {
731 char buf[255+1]; /* was originally MAXVIEWNAMELENGTH aka 15 bytes, however "meaningless name restrictions for Views and InvItems" was removed in 8bb1bfa30610f3c3291029b2c05e6e5b37415269 */
732 if(!AF_read_string(a->f, buf, sizeof buf)) ERR(AOE_views);
733 if(!is_zeroterminated(buf, sizeof buf)) ERR(AOE_views);
734 a->viewnames[i] = strdup(buf);
737 if(a->version >= 31) { // 2.7.0
738 a->inventorynames = malloc(a->game.inventorycount*sizeof(char*));
739 for(i=0; i<a->game.inventorycount; ++i) {
740 char buf[20]; /* MAX_SCRIPT_NAME_LEN */
741 if(!AF_read_string(a->f, buf, sizeof buf)) ERR(AOE_inventories);
742 if(!is_zeroterminated(buf, sizeof buf)) ERR(AOE_inventories);
743 a->inventorynames[i] = strdup(buf);
746 if(a->version >= 32) { // 2.7.2
747 /* here follow dialog script names */
752 /* prevent usage of uninitialized data */
753 if(!a->inventorynames) a->game.inventorycount = 0;
754 if(!a->viewnames) a->game.viewcount = 0;
756 /* at this point we have everything we need */
757 return AOE_success;
758 #undef FAIL
759 #undef ERR